C#中的代码简洁性—压缩一个setter,如果为null则抛出
在C#的早期版本中,如果希望防止空引用异常,则需要防御性地构建setter:C#中的代码简洁性—压缩一个setter,如果为null则抛出,c#,getter-setter,setter,C#,Getter Setter,Setter,在C#的早期版本中,如果希望防止空引用异常,则需要防御性地构建setter: public Guid ItemId { get; set; } //foreign key, required private Item _item; public virtual Item Item { get { return _item; } set { if(value == null) throw new ArgumentNullException(nameof(value))
public Guid ItemId { get; set; } //foreign key, required
private Item _item;
public virtual Item Item {
get {
return _item;
}
set {
if(value == null) throw new ArgumentNullException(nameof(value));
_item = value;
ItemId = value.ItemId;
}
}
对于更现代的实现,可以使用空合并运算符和表达式体将其压缩到一定量:
private Item _item;
public virtual Item Item {
get => _item;
set => _item = value ?? throw new ArgumentNullException(nameof(value));
}
然而,我很好奇,这是否能完全归结为标准参考的变化:
public virtual Item Item { get; set; }
这样您就不必定义私有项
建议?或者第二个代码块是否像我所能得到的那样高效/简单
我正在寻找一个在当前C#框架内的解决方案,而不是我必须花钱的东西。目前我的用例主张不支持付费产品免责声明:这些是将无效分配过滤到属性中的潜在“替代”方法。这可能无法直接回答这个问题,而是给出了如何在不定义私有属性和明确定义
getters
和setters
的情况下更一般地进行操作的思路
根据项
实际是什么,您可能可以通过将其创建为结构来创建项
的不可为空
类型
不可为空的类型被称为structs
。它们不是什么新东西,它们是允许存储int、string、bool等类型属性的值类型
截至MSDN:
结构类型是通常用于封装的值类型
相关变量的小组,例如
矩形或库存中项目的特征
以下示例显示了一个简单的结构声明:
编辑(Struct
如果对象
应该是不可为空的类型
,但是如果我们讨论的是类的属性,那么请阅读下文。):
另一种方法是使用OnPropertyChanged
事件,它是INotifyPropertyChanged
接口的一部分
虽然事件没有显式地为您提供已更改为的值,但您可以获取它,因为它确实为您提供了属性名称。所以你可以运行你的验证后分配,然后抛出,我想这可能不是最好的选择
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var propertyValue = sender.GetType().GetProperty(e.PropertyName).GetValue(sender);
}
另一个解决方案是使用DataAnnotations
并在属性上添加Required
属性。如果我没有弄错的话,他们不会马上扔掉,除非你调用你自己的validate函数来验证这个类,我想,结合上面的方法,这会很好地工作,而且会很通用。一旦编写完成,您就不必显式地编写getter
和setter
,而是只将一个事件附加到类中,并在属性更改后验证它
下面是一个小例子:
例如,您的项目
模型
public class Item
{
[Required]
public string Name { get; set; }
}
然后,您将实现一个验证所有属性的通用函数
public bool TryValidate(object @object, out ICollection < ValidationResult > results) {
var context = new ValidationContext(@object, serviceProvider: null, items: null);
results = new List <ValidationResult> ();
return Validator.TryValidateObject(
@object, context, results,
validateAllProperties: true
);
}
public bool TryValidate(object@object,out-ICollectionresults){
var context=new ValidationContext(@object,serviceProvider:null,items:null);
结果=新列表();
返回Validator.TryValidateObject(
@对象、上下文、结果、,
validateAllProperties:true
);
}
在该函数中,如果验证失败,您当然会抛出一个异常,results
数组将包含它在默认消息中失败的属性(如果我没有弄错的话)。我认为这有点复杂,但如果您希望减少属性和setter
实现的数量,这可能是一个进步。我不确定开销等。我个人认为,在更大范围内,这对于验证从db数据或任何外部源动态创建的模型非常有用
| | |研究面向方面的编程,PostSharp。我实际上是在当前的C#框架内寻找解决方案,而不是我必须花钱的东西。现在,我的用例主张不支持付费产品。“C#中的代码简洁性”在您的问题中。我继续把你评论中的附加信息放在你的问题中,这会影响潜在答案的有效性。下次你可以自己点击,你也可能想读。也许只是我,但我一直认为标题是整个帖子的组成部分,也是问题本身的一部分。除非标题与内容真正隔离,并且与内容没有关系?从大量的位置来看,这将是一个严重的问题。例如,在structI中编辑get/set可能会更明确一些,但我的目的是使其尽可能通用,以避免其他问题纠缠在一起。这适用于使用域实体的简单MVC5、存储库模式、DDD。我不确定结构在这方面有什么帮助(以前从未使用过结构),因为我是根据代码优先原则“使用”数据库中的表和字段的。@RenéKåbis我不知道结构如何使它在您的情况下比标准类对象更通用,并停止您上面所说的任何事情。如果
项
不为null,则将其设置为不可为null的类型(struct)就足够了。如果您正在谈论项中的特定属性
,请阅读我的编辑。
public bool TryValidate(object @object, out ICollection < ValidationResult > results) {
var context = new ValidationContext(@object, serviceProvider: null, items: null);
results = new List <ValidationResult> ();
return Validator.TryValidateObject(
@object, context, results,
validateAllProperties: true
);
}