如何在.NET 2.0中实现自定义属性?

问题描述:

不幸的是我仍在使用.NET 2.0。我以前没有创建过自定义属性。 我想创建一个CustomStringFormatAttribute:。如何在.NET 2.0中实现自定义属性?

如果一个类,说Customer.Name,具有:

MaxLength=30 
ActualLength=10 

我需要与空的空间填充它,直到它达到30

我还需要一个属性,我可以格式日期像DisplayDataFormat

我创建的属性内的财产的实际价值以下,但我如何获得?

public class Customer 
{ 
    [CustomStringFormatAttribute(30)] 
    public string Name { get; set; } 

    //todo:customDateAttribute 
    public DateTime StartDate { get; set; } 
} 

[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = true)] 
public sealed class CustomStringFormatAttribute : Attribute 
{ 
    private readonly int maxLength; 

    public CustomStringFormatAttribute(int maxLength) 
    { 
     MaxLength = maxLength; 
    } 

    public int MaxLength { get; private set; } 

    //?Should I override ToString 
    public override string ToString() 
    { 
     return Format(); 
    } 

    private string Format() 
    { 
     //simplified version of my formatting for brevity 
     string source = "value from the property of the class.";//How do I get access to the actual value of the property within the attribute? 
     const char paddingChar = ' '; 
     return source.PadLeft(maxLength, paddingChar); 
    }  
} 

有什么建议?

注:I”使用自动属性简洁。我在.NET 2.0中没有这种奢侈。

+2

这是不是很清楚你要完成什么,但它是你使用不当的属性可能。属性与类型相关联,而不与该类型的对象相关联。如果你需要一个特定对象的自定义显示格式,那么你*有*使用普通属性。 –

对不起,你不能访问类的实例或您的属性中的属性信息。 你应该在一些“静态”类中编写一个额外的方法,例如一个静态方法,它允许你做你想做的事情。

例....

public static string FormatProperty(object instance, PropertyInfo property) 
    { 
     CustomStringFormatAttribute attrib = Attribute.GetCustomAttribute(property, typeof(CustomStringFormatAttribute)) as CustomStringFormatAttribute; 
     return property.GetValue(instance, null).ToString().PadLeft(attrib.MaxLength, ' '); 
    } 

    public static string FormatProperty(object instance, string propertyName) 
    { 
     return FormatProperty(instance, instance.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance)); 
    } 

但是,这是非常不舒服,而且出奇的慢,因为使用反射来通过属性信息获取属性值。

要访问属性的属性,你需要的PropertyInfo。

public static int GetPropertyMaxLength(PropertyInfo property) 
    { 
     CustomStringFormatAttribute attrib = Attribute.GetCustomAttribute(property, typeof(CustomStringFormatAttribute)) as CustomStringFormatAttribute; 
     return attrib != null ? attrib.MaxLength : int.MaxValue; 
    } 

    public static int GetPropertyMaxLength(Type type, string propertyName) 
    { 
     return GetPropertyMaxLength(type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance)); 
    } 

让我们假设我们把这些函数放在属性中。 然后我们想重写我们的Customer类中的ToString方法。

public override string ToString() 
{ 
    return CustomStringFormatAttribute.FormatProperty(this, "Name"); 
} 

的问题,这是当然的速度,它使用的名字,很慢,而且重构反射,你不会有一个编译时警告或错误,如果“名称”属性不存在,你会运行时只能得到一个异常。我建议你使用另一种机制。

有了你可以使用lambda表达式直接由酒店本身获得你的财产信息的语言的新版本,但因为你是C#2.0中这是不可能的。

另一种解决方案可以是:添加,而不是所谓的FormattedXXX另一个属性,只要你想它,你可以使用该财产,而不是名称属性,返回lenght例子FormattedName。 这将允许您保留您的财产附近的财产的格式版本。

+0

谢谢你的答复。如果我的理解是正确的,你说什么,我没有获得任何使用属性。我想知道MS如何实现这一点[DisplayFormat(DataFormatString =“{0:C}”)] – user712923

+0

他们以我向你展示的方式......通过反思。 –

+0

而不是获取值,但可能只能反射以获取关联的属性而不是属性值,但它取决于您的应用程序。 –

你需要反过来做。你的属性中不应该有任何逻辑,它应该简单地暴露属性与它包含的信息(例如MaxLength属性)。然后你Customer类应该访问由CustomStringFormatAttribute提供的信息,并相应地格式化:

private string m_Name; 

public string Name 
{ 
    get 
    { 
     var formatAttribute = typeof(Customer).GetCustomAttributes(false) 
            .OfType<CustomStringFormatAttribute> 
            .SingleOrDefault(); 

     if (formatAttribute != null) 
      return m_Name.PadLeft(formatAttribute.MaxLength); 

     return m_Name; 
    } 
    set 
    { 
     m_Name = value; 
    } 
} 
+0

GetCustomAttributes()。OfType比使用Attribute.GetCustomAttribute慢,并且他没有linq,因为它是C#2.0。 –

+1

@SalvatorePreviti:如何精确地编码外观并不重要。这是属性保存由其他类访问的元数据的概念,而属性本身实际上并不做任何事情。是的,你可以微观优化(例如,通过将结果属性保存在某处而不是每次通过反射访问它),但这不是我的观点。另外,使用.NET 2.0不能免除您使用LINQ的责任。你有没有听说过[LINQBridge](http://linqbridge.googlecode.com)? –