如何确定是否需要 属性?
How to determine if a property is required?
给定一个 class 这样的东西:
public class MyClass : ValidationValues
{
public string Foo { get; set; }
[Required(ErrorMessage = "Bar is required.")]
public string Bar { get; set; }
// and many more
}
public class ValidationValues
{
public bool IsValid { get; set; } = true;
public string InvalidReason { get; set; }
}
我需要确定是否需要 属性,同时将其作为通用列表进行循环。通过查看 Watch,我找到了一种方法,但感觉很笨拙,我认为它应该更简单。
对于某些上下文,此逻辑在 Azure 函数内部。所以没有视图,没有 MVC 等。该功能是一个 Blob 存储触发器,它选择一个带有 | 的 .CSV 文件。被反序列化为 List<MyClass>
的定界列表。我们不想在反序列化时强制执行 Required
属性,因为我们想要更精细的控制。
所以给定一个这样的文件:
value1 | |
value2 | something
最终返回给用户的是这样的:
[
{
"foo": "value1",
"bar": "",
"isValid": false,
"InvalidReason" : "Bar is required"
},
{
"foo": "value2",
"bar": "something",
"isValid": true,
"InvalidReason" : ""
}
]
这是我现在拥有的:
foreach (T item in itemList) // where 'itemList' is a List<T> and in this case T is MyClass
{
foreach (PropertyInfo property in item.GetType().GetProperties())
{
if (property.CustomAttributes.ToList()[0].AttributeType.Name == "RequiredAttribute")
{
// validate, log, populate ValidationValues
}
}
}
这是我不喜欢的部分:
property.CustomAttributes.ToList()[0].AttributeType.Name == "RequiredAttribute"
有时当我想出一个编码挑战时,我告诉自己,“就是这样”。但在这种情况下,我很确定这不是方法。
反射很慢 - 或者至少相对较慢。所以;这里最重要的是:不要对每个 instance 执行此操作;您可以根据 Type
(来自 GetType()
)缓存它,或者您可以只使用 T
而从不检查每个实例的 .GetType()
,具体取决于您的意图。这包括缓存给定类型存在的属性,并且是必需的。但是,真正的奖励点是使用 meta-programming 发出 - 在运行时,或在 build-time 通过“生成器” - 一种方法*完全按照您的意愿行事,没有任何循环、测试等;即在这种情况下,它可能会发出一个方法,该方法相当于
void ValidateMyClass(MyClass obj)
{
if (string.IsNullOrWhitespace(obj.Bar))
{
DoSomething("Bar is required.");
}
}
这可以通过多种方式完成,包括 Expression
API、发射 API (ILGenerator
)、发射 C# 和使用 CSharpCodeProvider
,或“生成器”API.
您可以使用 GetCustomAttibute
:
重写该行
using System.Reflection;
foreach (T item in itemList) // where 'itemList' is a List<T> and in this case T is MyClass
{
foreach (PropertyInfo property in item.GetType().GetProperties())
{
var attribute = property.GetCustomAttibute<RequiredAttribute>();
}
}
给定一个 class 这样的东西:
public class MyClass : ValidationValues
{
public string Foo { get; set; }
[Required(ErrorMessage = "Bar is required.")]
public string Bar { get; set; }
// and many more
}
public class ValidationValues
{
public bool IsValid { get; set; } = true;
public string InvalidReason { get; set; }
}
我需要确定是否需要 属性,同时将其作为通用列表进行循环。通过查看 Watch,我找到了一种方法,但感觉很笨拙,我认为它应该更简单。
对于某些上下文,此逻辑在 Azure 函数内部。所以没有视图,没有 MVC 等。该功能是一个 Blob 存储触发器,它选择一个带有 | 的 .CSV 文件。被反序列化为 List<MyClass>
的定界列表。我们不想在反序列化时强制执行 Required
属性,因为我们想要更精细的控制。
所以给定一个这样的文件:
value1 | |
value2 | something
最终返回给用户的是这样的:
[
{
"foo": "value1",
"bar": "",
"isValid": false,
"InvalidReason" : "Bar is required"
},
{
"foo": "value2",
"bar": "something",
"isValid": true,
"InvalidReason" : ""
}
]
这是我现在拥有的:
foreach (T item in itemList) // where 'itemList' is a List<T> and in this case T is MyClass
{
foreach (PropertyInfo property in item.GetType().GetProperties())
{
if (property.CustomAttributes.ToList()[0].AttributeType.Name == "RequiredAttribute")
{
// validate, log, populate ValidationValues
}
}
}
这是我不喜欢的部分:
property.CustomAttributes.ToList()[0].AttributeType.Name == "RequiredAttribute"
有时当我想出一个编码挑战时,我告诉自己,“就是这样”。但在这种情况下,我很确定这不是方法。
反射很慢 - 或者至少相对较慢。所以;这里最重要的是:不要对每个 instance 执行此操作;您可以根据 Type
(来自 GetType()
)缓存它,或者您可以只使用 T
而从不检查每个实例的 .GetType()
,具体取决于您的意图。这包括缓存给定类型存在的属性,并且是必需的。但是,真正的奖励点是使用 meta-programming 发出 - 在运行时,或在 build-time 通过“生成器” - 一种方法*完全按照您的意愿行事,没有任何循环、测试等;即在这种情况下,它可能会发出一个方法,该方法相当于
void ValidateMyClass(MyClass obj)
{
if (string.IsNullOrWhitespace(obj.Bar))
{
DoSomething("Bar is required.");
}
}
这可以通过多种方式完成,包括 Expression
API、发射 API (ILGenerator
)、发射 C# 和使用 CSharpCodeProvider
,或“生成器”API.
您可以使用 GetCustomAttibute
:
using System.Reflection;
foreach (T item in itemList) // where 'itemList' is a List<T> and in this case T is MyClass
{
foreach (PropertyInfo property in item.GetType().GetProperties())
{
var attribute = property.GetCustomAttibute<RequiredAttribute>();
}
}