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

C#停止将自定义属性应用于类,c#,properties,attributes,custom-attributes,C#,Properties,Attributes,Custom Attributes,我在C#中创建了一个自定义属性: [AttributeUsage(AttributeTargets.Property,Inherited=false,AllowMultiple=false)] 公共类ExampleAttribute:属性 { } 我希望这只适用于属性,但更具体地说,是不是类(只是基类型)的属性 例如: 公共类示例POCO { //这些应该很好。。。 [示例] 公共字符串Prop1{get;set;} [示例] 公共bool Prop2{get;set;} [示例] 公共int

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

[AttributeUsage(AttributeTargets.Property,Inherited=false,AllowMultiple=false)]
公共类ExampleAttribute:属性
{
}
我希望这只适用于属性,但更具体地说,是不是类(只是基类型)的属性

例如:

公共类示例POCO
{
//这些应该很好。。。
[示例]
公共字符串Prop1{get;set;}
[示例]
公共bool Prop2{get;set;}
[示例]
公共int Prop3{get;set;}
//但这是不允许的,因为它是类,而不是基类型
[示例]
公共OtherExample Prop4{get;set;}
}
公共类示例
{
公共字符串Other1{get;set;}
}
有人知道我如何在编译时进一步限制这个自定义属性吗?如果这只能在运行时完成,那么最好的方法是什么


提前谢谢

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

想到的一些例子是Newtonsoft的
JsonConverter
属性,它要求构造函数中的类型实现一个特定的接口,或者Asp.Net的
Route
属性,它对语法和歧义有约束。这些东西可以作为Roslyn扩展实现,但最常见的约定是在运行时进行验证

即时验证是您声明所有需要验证的类型(或约定)并立即完成验证的地方。为此声明类型的一些方法包括:

  • 类型
    s的显式列表传递给
    验证
    方法
  • 创建一个接口,传入一个程序集,并扫描程序集以查找实现该接口的类型
  • 生成一个属性,传入一个程序集,并扫描该程序集以查找用它注释的类型
惰性验证是仅在使用类型时对其进行验证的地方。这具有启动时间更快的优点,但也意味着任何具有无效属性用法的类型在使用之前都不会被检测到

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

为了验证类型是否具有不正确的属性用法,可以使用如下方法:

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");
    }
}
private静态只读类型[]基元类型=新类型[]
{
类型(字符串),
类型(int),
类型(bool),
typeof(int?,//是否允许使用可为空的基元类型?由您决定
}
公共静态无效验证(类型)
{
var properties=type.GetProperties();
foreach(属性中的var属性)
{
var attribute=property.GetCustomAttribute();
if(属性==null)
继续;
如果(!Array.Contains(PrimitiveTypes,property.PropertyType))
抛出新异常(“为此场景创建自定义异常类型和消息”);
}
}

在本例中,为了简单起见,如果验证失败,我将抛出一个异常。如果您创建一个验证错误列表并返回这些错误,那么它将有助于调试,这样用户就可以看到所有的错误,而不仅仅是第一个错误。

您无法在编译时阻止这种情况发生。您在运行时如何处理这种情况?请参阅。