C#停止将自定义属性应用于类



我在C#中创建了一个自定义属性:

[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public class ExampleAttribute : Attribute
{
}

我希望这只应用于属性,但更具体地说,不是类(只是基类型(的属性。

示例:

public class ExamplePoco
{
// These should be fine...
[Example]
public string Prop1 { get; set; }
[Example]
public bool Prop2 { get; set; }
[Example]
public int Prop3 { get; set; }
// But this shouldn't be allowed because it's a class, rather than base type
[Example]
public OtherExample Prop4 { get; set; }
}
public class OtherExample
{
public string Other1 { get; set; }
}

有人知道我在编译时如何进一步限制这个自定义属性吗?如果这只能在运行时完成,那么最好的方法是什么?

提前感谢!

在编译时使用直接C#可以强制执行的数量是有限的。正如评论中所指出的,可以编写一个自定义Roslyn扩展来查找无效用法。这是一个相当繁重的解决方案——大多数人倾向于在运行时实现这类事情的验证,而不是在编译时。

脑海中出现的一些例子是Newtonsoft的JsonConverter属性,它要求构造函数中的类型实现特定的接口,或者Asp.Net的Route属性,它对语法和模糊性有限制。这些可以作为Roslyn扩展来实现,但最常见的约定是在运行时进行验证。

Eager Validation是声明所有需要验证的类型(或约定(的地方,并且验证是直接完成的。为此声明类型的一些方法包括:

  • Types的显式列表传递给Validate方法
  • 生成接口,传入程序集,然后扫描程序集以查找实现该接口的类型
  • 生成一个属性,传入一个程序集,然后扫描程序集以查找用它进行注释的类型

懒惰验证是指仅在使用类型时才对其进行验证。这具有启动时间更快的优点,但也意味着任何具有无效属性使用的类型在使用之前都不会被检测到。

验证使用反射,并且可能会对性能造成很大影响,因此,如果您确实决定进行延迟验证,那么您肯定应该缓存结果。

为了验证一个类型是否有不正确的属性用法,您可以制作如下方法:

private static readonly Type[] PrimitiveTypes = new Type[]
{
typeof(string),
typeof(int),
typeof(bool),
typeof(int?), // Are nullable primitive types allowed? You decide
}
public static void Validate(Type type)
{
var properties = type.GetProperties();
foreach (var property in properties)
{
var attribute = property.GetCustomAttribute<ExampleAttribute>();
if (attribute == null)
continue;
if (!Array.Contains(PrimitiveTypes, property.PropertyType))
throw new Exception("Make a custom exception type and message for this scenario");
}
}

在这个例子中,如果验证失败,我会抛出一个异常,只是为了保持简单。相反,如果您列出验证错误并返回它们,这样用户就可以看到所有错误,而不仅仅是第一个错误,那么这对调试很有帮助。

最新更新