C#检查属性内部或外部的值?

时间:2017-10-04 10:33:41

标签: c#

我写了两个代码,我不确定哪个代码更好或更干净。在第一个代码中,我检查属性中的名字和姓氏是否为空,在第二个代码中,我在确定属性之前检查名字和姓氏是否为空。我已经使用了这两种方法,但我想开始编写干净的代码,希望有人可以告诉我他们喜欢什么或者我应该使用什么。

第一个代码:

public class Program
{
    public static void Main(string[] args)
    {
    try
    {
        Person p = new Person(null, null);
    }
    catch(Exception e)
    {
        Console.WriteLine(e.Message);
    }

    Console.ReadKey();
    }
}

public class Person
{
    private string firstName;
    private string lastName;

    public Person(string firstName, string lastName)
    {
        this.FirstName = firstName;
        this.LastName = lastName;
    }

    public string FirstName
    {
        get
        {
            return this.firstName;
        }
        set
        {
            if (firstName == null)
            {
                throw new NullReferenceException("The first name must not be null!");
            }

            this.firstName = value;
        }
    }

    public string LastName
    {
        get
        {
            return this.lastName;
        }
        set
        {
            if (lastName == null)
            {
                throw new NullReferenceException("The last name must not be null!");
            }

            this.lastName = value;
        }
    }
}

或:

public class Program
{
    public static void Main(string[] args)
    {
        string firstName = null;
        string lastName = null;

        try
        {
            if (firstName == null)
            {
                throw new NullReferenceException("The first name must not be null!");
            }
            else if (lastName == null)
            {
                throw new NullReferenceException("The last name must not be null!");
            }
            else
            {
                Person p = new Person(firstName, lastName);
            }
        }
        catch(Exception e)
        {
            Console.WriteLine(e.Message);
        }

        Console.ReadKey();
    }
}

public class Person
{
    public Person(string firstName, string lastName)
    {
        this.FirstName = firstName;
        this.LastName = lastName;
    }

    public string FirstName
    {
        get;
        set;
    }

    public string LastName
    {
        get;
        set;
    }
}

2 个答案:

答案 0 :(得分:0)

  

使用第一个在Person类中进行微小更改。

或者,如果您使用的是MVC模型,则可以使用数据注释。

public class Person
{
    [Required(ErrorMessage = "First Name is required!")]
    public string FirstName { get; set; }

    [Required(ErrorMessage = "Second Name is required!")]
    public string SecondName { get; set; }
}

不是检查firstname和lastname是否为null,而是检查传入的值。

优点:

  1. 验证逻辑不需要分散在各个类中。

  2. 您可以创建第三个属性以获取全名。

      public class Person
       {
    
        private string firstName;
    
        private string lastName;
    
        public Person(string firstName, string lastName)
        {
            this.FirstName = firstName;
            this.LastName = lastName;
        }
    
        public string FirstName
        {
            get
            {
                return this.firstName;
            }
            set
            {
                if (value == null)
                {
                    throw new NullReferenceException("The first name must not be null!");
                }
    
                this.firstName = value;
            }
        }
    
        public string LastName
        {
            get
            {
                return this.lastName;
            }
            set
            {
                if (value == null)
                {
                    throw new NullReferenceException("The last name must not be null!");
                }
    
                this.lastName = value;
            }
        }
    

答案 1 :(得分:0)

这取决于您需要验证的原因。

如果你使用MVVM(我认为你会这样,因为这个类叫做Person),我会建议实现ReactiveUI接口和INotifyPropertyChanged(我使用AutoMapper)。如果在MVVM中使用异常进行验证,则无法检查与UI绑定的模型是否有效,因为实际上没有为您的属性设置无效值。

这意味着,在所有数据都有效之前,禁用“确定”按钮等逻辑的简单部分必须移动到用户界面。

如果您还想序列化Person类,请在派生的PersonValidation类中进行检查,否则您将在许多奇怪的地方进行exeptions。

另一个完整问题是字符串以外的类型属性,如int。

我发现最简单的方法(我并不认为它是最好的)是为每个非字符串属性设置一个字符串属性,并将UI文本框绑定到字符串。

     class Person // this is your DTO, for serialization (to JSON and so on) and this goes to database
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public int Age { get; set; }
        }

        class PersonVM : ReactiveObject // this is your object to display in UI
        {
            private string _firstName;
            private string _lastName;
            private int _age;

            public string FirstName
            {
                get { return _firstName; }
                set { this.RaiseAndSetIfChanged(ref _firstName, value); }
            }

            public string LastName
            {
                get { return _lastName; }
                set { this.RaiseAndSetIfChanged(ref _lastName, value); }
            }

            public int Age
            {
                get { return _age; }
                set { this.RaiseAndSetIfChanged(ref _age, value); }
            }
        }

       class PersonVMValidation : PersonVM, INotifyDataErrorInfo // this is your validation class, where you can check if the whole object is valid
{
    public PersonVMValidation()
    {
        this.WhenAnyValue(x => x.AgeString).Subscribe(_ =>
        {
            if (Int32.TryParse(AgeString, out int age))
            {
                if (age >= 0)
                {
                    Age = age;
                    SetError("Age", null);
                }
                else
                {
                    SetError("Age", "Age has to be >= 0");
                }
                //and so on
            }
            else
            {
               // you reset age to 0 for example
               SetError("Age", "Age has to be numeric");
            }
        });

        // do the same for LastName
        this.WhenAnyValue(x => x.FirstName).Subscribe(_ =>
        {
            if (string.IsNullOrEmpty(FirstName))
            {
                SetError("FirstName", "First name cannot be empty");
            }
            else
            {
                SetError("FirstName", null);
            }
        });
    }

    public string AgeString
    {
        get { return _ageString; }
        set { this.RaiseAndSetIfChanged(ref _ageString, value); }
    }

    protected Dictionary<string, List<string>> ErrorsDictionary = new Dictionary<string, List<string>>();
    private bool _hasErrors;
    private string _ageString;


    protected void SetError(string property, string error)
    {
        ErrorsDictionary[property] = new List<string>();
        if (error != null)
        {
            ErrorsDictionary[property].Add(error);
            HasErrors = true;
        }
        else
        {
            if (ErrorsDictionary.All(x => !x.Value.Any()))
                HasErrors = false;
        }

        ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs("Value"));
    }

            var person = someservice.GetPerson();

            PersonVMValidation personValidation = Mapper.Map<PersonVMValidation>(person); // notice no exceptions here, you bind UI to this

            var canSaveCahnges = personValidation.WhenAnyValue(x => x.HasErrors).Select(x => !x);
            SaveChanges = ReactiveCommand.Create(() =>
            {
/*do stuff*/
            }, canSaveCahnges);

使用https://www.w3schools.com/cssref/pr_class_position.asp创建PersonVM表单Person并返回。

那是用WPF创建的UI应用程序,它有很好的内置技巧来显示这些错误。

如果您使用MVC,请使用@Amit的答案。

如果你想要它用于其他东西,我认为从contructor设置属性并检查你的条件(并隐藏setter) - 这将允许你轻松捕获那些NullArgumentExceptions。