我写了两个代码,我不确定哪个代码更好或更干净。在第一个代码中,我检查属性中的名字和姓氏是否为空,在第二个代码中,我在确定属性之前检查名字和姓氏是否为空。我已经使用了这两种方法,但我想开始编写干净的代码,希望有人可以告诉我他们喜欢什么或者我应该使用什么。
第一个代码:
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;
}
}
答案 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,而是检查传入的值。
优点:
验证逻辑不需要分散在各个类中。
您可以创建第三个属性以获取全名。
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。