为什么 C# 禁止泛型属性类型?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/294216/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 21:59:07  来源:igfitidea点击:

Why does C# forbid generic attribute types?

c#generics.net-attributes

提问by Bryan Watts

This causes a compile-time exception:

这会导致编译时异常:

public sealed class ValidatesAttribute<T> : Attribute
{

}

[Validates<string>]
public static class StringValidation
{

}

I realize C# does not support generic attributes. However, after much Googling, I can't seem to find the reason.

我意识到 C# 不支持通用属性。但是,经过多次谷歌搜索,我似乎找不到原因。

Does anyone know why generic types cannot derive from Attribute? Any theories?

有谁知道为什么不能从泛型派生Attribute?有什么理论吗?

采纳答案by Jon Skeet

Well, I can't answer why it's not available, but I canconfirm that it's not a CLI issue. The CLI spec doesn't mention it (as far as I can see) and if you use IL directly you can create a generic attribute. The part of the C# 3 spec that bans it - section 10.1.4 "Class base specification" doesn't give any justification.

好吧,我无法回答为什么它不可用,但我可以确认这不是 CLI 问题。CLI 规范没有提到它(据我所知),如果您直接使用 IL,您可以创建一个通用属性。C# 3 规范中禁止它的部分 - 第 10.1.4 节“类基础规范”没有给出任何理由。

The annotated ECMA C# 2 spec doesn't give any helpful information either, although it does provide an example of what's not allowed.

带注释的 ECMA C# 2 规范也没有提供任何有用的信息,尽管它确实提供了一个不允许的示例。

My copy of the annotated C# 3 spec should arrive tomorrow... I'll see if that gives any more information. Anyway, it's definitely a language decision rather than a runtime one.

我的带注释的 C# 3 规范的副本应该会在明天到达...我会看看是否能提供更多信息。无论如何,这绝对是语言决定而不是运行时决定。

EDIT: Answer from Eric Lippert (paraphrased): no particular reason, except to avoid complexity in both the language and compiler for a use case which doesn't add much value.

编辑:Eric Lippert 的回答(释义):没有特别的原因,除了避免语言和编译器的复杂性,因为用例不会增加太多价值。

回答by GalacticCowboy

An attribute decorates a class at compile-time, but a generic class does not receive its final type information until runtime. Since the attribute can affect compilation, it has to be "complete" at compile time.

属性在编译时修饰类,但泛型类直到运行时才会收到其最终类型信息。由于该属性会影响编译,因此在编译时它必须是“完整的”。

See this MSDN articlefor more information.

有关更多信息,请参阅此MSDN 文章

回答by ichiban

This is a very good question. In my experience with attributes, I think the constraint is in place because when reflecting on an attribute it would create a condition in which you would have to check for all possible type permutations: typeof(Validates<string>), typeof(Validates<SomeCustomType>), etc...

这个问题问得好。在我与属性的经验,我认为约束是在地方,因为一个属性反映时,将创建您必须检查所有可能的排列型的条件:typeof(Validates<string>)typeof(Validates<SomeCustomType>),等...

In my opinion, if a custom validation is required depending on the type, an attribute may not be the best approach.

在我看来,如果根据类型需要自定义验证,则属性可能不是最佳方法。

Perhaps a validation class that takes in a SomeCustomValidationDelegateor an ISomeCustomValidatoras a parameter would be a better approach.

也许将 aSomeCustomValidationDelegate或 anISomeCustomValidator作为参数的验证类会是更好的方法。

回答by GeekyMonkey

I don't know why it's not allowed, but this is one possible workaround

我不知道为什么不允许这样做,但这是一种可能的解决方法

[AttributeUsage(AttributeTargets.Class)]
public class ClassDescriptionAttribute : Attribute
{
    public ClassDescriptionAttribute(Type KeyDataType)
    {
        _KeyDataType = KeyDataType;
    }

    public Type KeyDataType
    {
        get { return _KeyDataType; }
    }
    private Type _KeyDataType;
}


[ClassDescriptionAttribute(typeof(string))]
class Program
{
    ....
}

回答by nawfal

This is not truly generic and you still have to write specific attribute class per type, but you may be able to use a generic base interface to code a little defensively, write lesser code than otherwise required, get benefits of polymorphism etc.

这不是真正的通用,您仍然需要为每种类型编写特定的属性类,但是您可以使用通用基接口来进行一些防御性的编码,编写比其他要求更少的代码,获得多态的好处等。

//an interface which means it can't have its own implementation. 
//You might need to use extension methods on this interface for that.
public interface ValidatesAttribute<T>
{
    T Value { get; } //or whatever that is
    bool IsValid { get; } //etc
}

public class ValidatesStringAttribute : Attribute, ValidatesAttribute<string>
{
    //...
}
public class ValidatesIntAttribute : Attribute, ValidatesAttribute<int>
{
    //...
}

[ValidatesString]
public static class StringValidation
{

}
[ValidatesInt]
public static class IntValidation
{

}

回答by razon

My workaround is something like this:

我的解决方法是这样的:

public class DistinctType1IdValidation : ValidationAttribute
{
    private readonly DistinctValidator<Type1> validator;

    public DistinctIdValidation()
    {
        validator = new DistinctValidator<Type1>(x=>x.Id);
    }

    public override bool IsValid(object value)
    {
        return validator.IsValid(value);
    }
}

public class DistinctType2NameValidation : ValidationAttribute
{
    private readonly DistinctValidator<Type2> validator;

    public DistinctType2NameValidation()
    {
        validator = new DistinctValidator<Type2>(x=>x.Name);
    }

    public override bool IsValid(object value)
    {
        return validator.IsValid(value);
    }
}

...
[DataMember, DistinctType1IdValidation ]
public Type1[] Items { get; set; }

[DataMember, DistinctType2NameValidation ]
public Type2[] Items { get; set; }

回答by Owen Pauling

This is not currently a C# language feature, however there is much discussion on the official C# language repo.

这目前不是 C# 语言功能,但是在官方 C# 语言 repo 上有很多讨论

From some meeting notes:

来自一些会议笔记

Even though this would work in principle, there are bugs in most versions of the runtime so that it wouldn't work correctly (it was never exercised).

We need a mechanism to understand which target runtime it works on. We need that for many things, and are currently looking at that. Until then, we can't take it.

Candidate for a major C# version, if we can make a sufficient number of runtime versions deal with it.

尽管这在原则上是可行的,但大多数版本的运行时都存在错误,因此无法正常工作(从未执行过)。

我们需要一种机制来了解它在哪个目标运行时上工作。我们在很多事情上都需要它,目前正在研究这一点。在那之前,我们不能接受。

主要 C# 版本的候选者,如果我们可以让足够数量的运行时版本处理它。