为什么 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
Why does C# forbid generic attribute types?
提问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 SomeCustomValidationDelegate
or an ISomeCustomValidator
as 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# 版本的候选者,如果我们可以让足够数量的运行时版本处理它。