【问题标题】:C# stop custom attribute from being applied to classC#停止将自定义属性应用于类
【发布时间】:2021-03-02 06:55:22
【问题描述】:

我在 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# properties attributes custom-attributes


【解决方案1】:

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

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

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

  • 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");
    }
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-15
    • 2011-02-22
    • 2011-11-28
    • 1970-01-01
    • 1970-01-01
    • 2012-02-15
    相关资源
    最近更新 更多