简体   繁体   English

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

[英]C# stop custom attribute from being applied to class

I've created a custom property in C#:我在 C# 中创建了一个自定义属性:

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

I would like this to ONLY be applied to properties, but more specifically, properties that are not classes (just base types).我希望这仅适用于属性,但更具体地说,不是类(只是基本类型)的属性。

Example:例子:

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; }
}

Does anyone know how I'd further restrict this custom attribute at compile time?有谁知道我如何在编译时进一步限制这个自定义属性? If this can only be done at runtime, what is the best way to approach this?如果这只能在运行时完成,那么解决这个问题的最佳方法是什么?

Thanks in advance!提前致谢!

There is a limit to how much you can enforce at compile time with straight C#.在编译时使用直接 C# 可以强制执行的数量是有限的。 As has been pointed out in the comments, you can write a custom Roslyn extension to look for invalid usage.正如评论中指出的那样,您可以编写自定义 Roslyn 扩展来查找无效使用。 That's a fairly heavy solution - most people tend to implement validation of these sorts of things at runtime, not at compile time.这是一个相当繁重的解决方案 - 大多数人倾向于在运行时而不是在编译时实现对这类事情的验证。

Some examples that come to mind are Newtonsoft's JsonConverter attribute, which requires that the type in the constructor implements a specific interface, or Asp.Net's Route attribute, which has constraints on syntax and ambiguity.想到的一些例子是 Newtonsoft 的JsonConverter属性,它要求构造函数中的类型实现特定的接口,或者 Asp.Net 的Route属性,它对语法和歧义有限制。 These things could be implemented as a Roslyn extension, but the most common convention is to validate at runtime.这些东西可以作为 Roslyn 扩展来实现,但最常见的约定是在运行时进行验证。

Eager Validation is where you declare all the the types (or a convention) that need to be validated, and the validation is done straight away. Eager Validation是您声明所有需要验证的类型(或约定)的地方,验证会立即完成。 Some ways to declare the types for this include:为此声明类型的一些方法包括:

  • Pass in an explicit list of Type s to the Validate methodType的显式列表传递给Validate方法
  • Make an interface, pass in an assembly, and scan the assembly for types that implement the interface制作一个接口,传入一个程序集,然后扫描程序集寻找实现该接口的类型
  • Make an attribute, pass in an assembly, and scan the assembly for types that are annotated with it创建一个属性,传入一个程序集,然后扫描程序集以查找用它注释的类型

Lazy validation is where you only validate a type when it is used.惰性验证是您仅在使用类型时对其进行验证的地方。 This has the advantage of faster startup times, but it also means any types that have invalid attribute usage will not be detected until they are used.这具有启动时间更快的优点,但这也意味着任何具有无效属性使用的类型在使用之前都不会被检测到。

Validation uses reflection, and can be quite a performance hit, so if you do decide to do lazy validation, you should definitely cache the results.验证使用反射,并且可能会对性能造成很大影响,因此如果您决定进行延迟验证,则绝对应该缓存结果。

In order to validate if a type has incorrect attribute usage, you could make a method like the following:为了验证类型是否具有不正确的属性使用,您可以创建如下方法:

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

In this example, I'm throwing an exception if the validation fails, just to keep it simple.在这个例子中,如果验证失败,我会抛出一个异常,只是为了简单起见。 It can be helpful for debugging if instead you make a list of validation errors, and return them, so the user can see all the errors instead of just the first one.如果您创建一个验证错误列表并返回它们,这对调试会很有帮助,这样用户就可以看到所有错误,而不仅仅是第一个错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM