如果您熟悉blazor,您就会知道EditForm组件*需要为它们提供一个模型。在这种情况下,提供的ViewModel既用于创建新实体,也用于创建从数据库中提取的现有实体。在一种情况下,ViewModel具有Id==null,而在另一种情况中,它具有现有实体的Id。创建ViewModel的最佳方式是什么?
其中一个可能有两个构造函数:
public class PersonViewModel
{
public PersonViewModel(String name, Int32 age)
{
if (String.IsNullOrWhiteSpace(name)) throw new InvalidOperationException($"{nameof(name)} is invalid");
if (age < 0) throw new InvalidOperationException($"{nameof(age)} is invalid");
Name = name;
Age = age;
}
public PersonViewModel(Guid id, String name, Int32 age)
{
if (id == Guid.Empty) throw new InvalidOperationException($"{nameof(id)} is invalid");
if (String.IsNullOrWhiteSpace(name)) throw new InvalidOperationException($"{nameof(name)} is invalid");
if (age < 0) throw new InvalidOperationException($"{nameof(age)} is invalid");
Id = id;
Name = name;
Age = age;
}
public Guid? Id { get; }
public String Name { get; }
public Int32 Age { get; }
}
这里有一个重复验证作为一个问题。
另一种方法是使用两种不同的静态方法,并将构造函数设为私有的,这会带来一些缺点,比如无法继承类并使用基构造函数:
public class PersonViewModel
{
private PersonViewModel() { }
public Guid? Id { get; private set; }
public String Name { get; init; }
public Int32 Age { get; init; }
public static PersonViewModel MakeWithoutId(String name, Int32 age)
{
if (String.IsNullOrWhiteSpace(name)) throw new InvalidOperationException($"{nameof(name)} is invalid");
if (age < 0) throw new InvalidOperationException($"{nameof(age)} is invalid");
return new()
{
Name = name,
Age = age,
};
}
public static PersonViewModel MakeWithId(Guid id, String name, Int32 age)
{
if (id == Guid.Empty) throw new InvalidOperationException($"{nameof(id)} is invalid");
var vm = PersonViewModel.MakeWithoutId(name, age);
vm.Id = id;
return vm;
}
}
我想有人可能会说,将id作为私有集而不是init是不好的,我本可以再次从头开始初始化它,但通过这种方式,我重用了以前方法中的代码和验证。或者我应该有两个独立的ViewModel类,其中一个继承或包含另一个,如NewPersonViewModel和ExistingPersonViewModel?
- 现在我考虑一下,EditForm输入中使用的属性应该有公共集,很抱歉我在随机文件中尝试了这个代码
我会将验证代码移得更靠近属性,这样你也可以使用公共setter。
public class PersonViewModel
{
private Guid? _id;
private string _name;
private int _age;
public Guid? Id
{
get { return _id; }
set
{
if (value == Guid.Empty) throw new InvalidOperationException($"{nameof(value)} is invalid");
_id = value;
}
}
public string Name
{
get { return _name; }
set
{
if (String.IsNullOrWhiteSpace(value)) throw new InvalidOperationException($"{nameof(value)} is invalid");
_name = value;
}
}
public int Age
{
get { return _age; }
set
{
if (value < 0) throw new InvalidOperationException($"{nameof(value)} is invalid");
_age = value;
}
}
public PersonViewModel(String name, Int32 age)
{
Name = name;
Age = age;
}
public PersonViewModel(Guid id, String name, Int32 age)
{
Id = id;
Name = name;
Age = age;
}
public static PersonViewModel GetInstance(String name, Int32 age)
{
return new PersonViewModel(name, age);
}
public static PersonViewModel GetInstance(Guid id, String name, Int32 age)
{
return new PersonViewModel(id, name, age);
}
}
测试
var pvm=PersonViewModel.GetInstance("New Name", 20); //ok
var pvm1=PersonViewModel.GetInstance(Guid.NewGuid(), "New Name", -1); //invalid age exception
我放了一个例外,因为你想要它。如果你只需要用户验证,只需要使用数据注释或流畅的验证。
或者你可以创建属性来显示错误消息,类似于这个
public string AgeErrorMessage {get; private set;}
public int Age
{
get { return _age; }
set
{
if (value < 0) AgeErrorMessage=$"{nameof(value)} is invalid";
else
{
AgeErrorMessage=string.Empty;
_age = value;
}
}
}