如何在C#中限制Process类的Exams属性仅使用指定Exam实例?
解决方案
要实现"确保Process.Exams中的对象都属于预定义集合"的需求,需要从预定义集合的暴露、限制Exam实例的创建、添加验证逻辑三个方面入手,具体步骤如下:
1. 改造预定义Exam集合的静态类
首先完善PossibleExams,对外暴露所有可用实例、完整集合,以及根据ID查找实例的方法,方便外部获取和后续验证:
public static class PossibleExams { // 公开单个预定义考试实例 public static readonly Exam Exam1 = new Exam(1, "Exam 1"); public static readonly Exam Exam2 = new Exam(2, "Exam 2"); public static readonly Exam Exam3 = new Exam(3, "Exam 3"); public static readonly Exam Exam4 = new Exam(4, "Exam 4"); public static readonly Exam Exam5 = new Exam(5, "Exam 5"); // 公开只读的完整可用考试集合,用于验证和遍历 public static IReadOnlyList<Exam> AllExams { get; } = new List<Exam> { Exam1, Exam2, Exam3, Exam4, Exam5 }.AsReadOnly(); // 根据ID获取预定义实例,避免外部随意创建 public static Exam GetById(int id) { return AllExams.FirstOrDefault(e => e.Id == id) ?? throw new ArgumentException($"不存在ID为{id}的预定义考试", nameof(id)); } }
2. 限制Exam实例的创建
为了防止外部代码随意创建不属于预定义集合的Exam实例,将Exam的构造函数设为internal(如果和PossibleExams在同一个程序集),只有预定义类能创建实例:
public class Exam { [Required] public int Id { get; } [Required] public string Name { get; } // 建议去掉?,因为构造时会校验非空 // 设为internal,仅同程序集的PossibleExams可调用 internal Exam(int id, string name) { Id = id; Name = name ?? throw new ArgumentNullException(nameof(name), "考试名称不能为空"); } }
3. 添加自定义验证确保合规
创建自定义验证属性,校验Process的Exams集合中所有实例都属于预定义集合:
public class ValidExamCollectionAttribute : ValidationAttribute { protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) { var exams = value as List<Exam>; if (exams == null) { return new ValidationResult("考试集合不能为空"); } foreach (var exam in exams) { if (!PossibleExams.AllExams.Contains(exam)) { return new ValidationResult($"ID为{exam.Id}的考试不属于预定义集合"); } } return ValidationResult.Success; } }
然后在Process类的Exams属性上添加该验证属性:
public class Process { public int Id { get; set; } [Required] public Person? Person { get; set; } [Required] [MinLength(1, ErrorMessage = "至少选择一项考试")] [ValidExamCollection] // 新增自定义验证 public List<Exam>? Exams { get; set; } [Required] [DataType(DataType.Date)] public DateTime ProcessDate { get; set; } }
使用示例
后续创建Process实例时,直接从PossibleExams获取Exam实例即可确保合规:
var validProcess = new Process { Person = new Person(), // 假设Person类已定义 Exams = new List<Exam> { PossibleExams.Exam1, PossibleExams.Exam3 }, ProcessDate = DateTime.Today };
内容的提问来源于stack exchange,提问作者Frixer
相关产品推荐
相关产品推荐

