为什么C#属性如此有限?

时间:2010-09-20 20:46:21

标签: c# attributes

我知道它们是编译时,所以它们不能是通用的,必须用常量值初始化。但是:
如果您反映出他们申请的内容,他们为什么不能获得您所获得的信息呢? 为什么他们不能接受lambda表达式,函数或委托?编译器的函数不是常量吗?

属性可以是一个非常强大的声明工具,只要上面的一个是真的,而不是它们更像是可以通过反射阅读的注释。

这有点像咆哮,但我真的想知道为什么它们看起来像是这样的半特征。

这是我想要做的。它应该是一个API,用于将资源中的值通过给定属性的函数映射到属性应用的属性。请注意,如果Attributes可以知道它们反映的内容,则抽象类不必存在。我发布这个是因为有人想知道我为什么要为属性构造函数赋予函数,也许是因为我要做的事情已经完成了。

public delegate void PropertyHandler(object parent, PropertyInfo property, object value);

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class FromResourceAttribute : Attribute
{
    private static readonly PropertyHandler m_defaultHandler =  (parent, property, value) => 
                                                                {
                                                                    property.SetValue(parent, value, null);
                                                                };

    public PropertyHandler Handler { get; set; }

    public FromResourceAttribute(PropertyHandler handler)
    {
        Handler = handler;
    }

    public FromResourceAttribute()
    {
        Handler = m_defaultHandler;
    }
}

public abstract class ResourceDependent
{
    public ResourceDependent(ResourceManager resources)
    {
        var resourceDependentProperties = 
            from property in GetType().GetProperties()
            let fromResourceAttributes = property.GetCustomAttributes(typeof(FromResourceAttribute), true)
            where fromResourceAttributes.Count() == 1
            let propertyHandler = ((FromResourceAttribute)fromResourceAttributes.Single()).Handler
            select new { Info = property, Handler = propertyHandler };

        foreach(var property in resourceDependentProperties)
        {
            property.Handler(this, property.Info, resources.GetObject(property.Info.Name));
        }
    }
}

class ResourceDependentTest : ResourceDependent
{
    [FromResource]
    public string Data { get; set; }

    [FromResource((parent, property, value) => property.SetValue(parent, ((string)value).Split('|'), null))]
    public string[] Data2 { get; set; }

    static PropertyHandler Data3Handler =   (parent, property, value) =>
                                            {
                                                //Magic
                                            };

    [FromResource(Data3Handler)]
    public int Data3 { get; set; }

    public ResourceDependentTest() : base(Properties.Resources.ResourceManager)
    {

    }
}

4 个答案:

答案 0 :(得分:11)

如果您反映出他们申请的内容,他们为什么不能获得您所获得的信息?

部分原因是属性不必应用于任何事物。在命令式代码中新建一个属性是完全合法的,这个属性没有附加到任何东西上。

// Not attached
var attrib = new CLSCompliantAttribute(false);

为什么他们不能接受lambda表达式,函数或委托?函数不是常量吗?

所有这些都解决了为什么委托不能成为属性的一部分的问题。核心代表由两部分组成:1)实例和2)指向方法的指针。 #1非常杀死它,因为实例不是常量,不能是属性值的一部分。

委托中还存在其他几种情况,包括静态方法和表达式树的委托。这些问题类似,但表达式的所有部分都不是常量,因此在属性值中不可编码。

答案 1 :(得分:5)

实际上,关于他们为什么不能通用的问题之前已经得到了解答,根据Eric Lippert的说法,他们不受支持只是因为他们会增加语言的复杂性,而且到目前为止还没有被认为值得做。这肯定不是因为它是编译时间。在IL中,你显然可以创建通用属性。 (Reference。)

至于为什么他们不能采用lambda表达式等,我想它也是同样的道理。 自2006年以来,代表的使用请求为Microsoft Connect 。如果您愿意,可以投票支持。

答案 2 :(得分:2)

简短的版本是IL不支持更多功能;请参阅ECMA-335分区II§21自定义属性和分区II§23.3自定义属性。

总结§23.3,自定义属性使用存储在IL中的自定义序列化格式,而不是Binary Serialization,而不是XML or SOAP序列化。引用标准§23.3:

  

FieldOrPropType应该是完全正确的   其中一个:ELEMENT_TYPE_BOOLEAN,   ELEMENT_TYPE_CHAR,   ELEMENT_TYPE_I1ELEMENT_TYPE_U1,   ELEMENT_TYPE_I2ELEMENT_TYPE_U2,   ELEMENT_TYPE_I4ELEMENT_TYPE_U4,   ELEMENT_TYPE_I8ELEMENT_TYPE_U8,   ELEMENT_TYPE_R4ELEMENT_TYPE_R8,   ELEMENT_TYPE_STRING。一个   单维,零基数组   被指定为单字节0x1D   其次是FieldOrPropType   元素类型。 (见§23.1.16)枚举   被指定为单字节0x55   接下来是一个SerString。跟随SerString。

当然,明显的反应是“为什么IL序列化格式不支持方法引用/等等。当然,明显的答案是他们认为没有必要和/或它会进一步膨胀IL。

(有趣的是:类型引用实际上是通过使用包含类型的完全限定程序集名称的字符串来实现的。通过相同的逻辑,我认为方法引用可以通过使用类型名称和“编码”来编码。该方法的编码,但我怀疑这将是“脆弱的”,因为添加/更改方法可能会破坏事物。)

答案 3 :(得分:1)

我不是很熟悉属性(因为在我看来它们是为像nunit这样的工具构建者制作的),但我想你已经回答了你的问题: 属性是编译时间常量

  

属性参数仅限于   以下常数值   类型:

* Simple types (bool, byte, char, short, int, long, float, and double)
* string
* System.Type
* enums
* object (The argument to an attribute parameter of type object
     

必须是其中一个的常量值   以上类型。)       *任何上述类型的一维阵列

http://msdn.microsoft.com/en-us/library/aa288454%28VS.71%29.aspx#vcwlkattributestutorialanchor1

而lambdas,delegates和functions的返回值不是。

我真的不想知道在属性中使用重型lambda的代码看起来会是什么样,应该是非常混乱。