【问题标题】:How can I implement custom attributes in .NET 2.0?如何在 .NET 2.0 中实现自定义属性?
【发布时间】:2011-11-05 08:43:31
【问题描述】:

不幸的是,我仍在使用 .NET 2.0。我之前没有创建自定义属性。 我想创建一个CustomStringFormatAttribute:。

如果一个类,比如 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);
    }    
}

有什么建议吗?

注意:为简洁起见,我使用了自动属性。我在 .NET 2.0 中没有这种奢侈。

【问题讨论】:

  • 不太清楚您要完成什么,但您可能不恰当地使用了属性。属性与类型相关联,而不是与该类型的对象相关联。如果您需要特定对象的自定义显示格式,那么您必须使用普通属性。

标签: c# .net .net-2.0 custom-attributes


【解决方案1】:

抱歉,您无法访问属性中的类实例或属性信息。 您应该编写一个额外的方法,例如某个“静态”类中的静态方法,它允许您做您想做的事情。

示例....

    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 的属性,例如 FormattedName,它可以根据需要返回长度,您可以使用该属性而不是 Name 属性。 这将允许您将属性的格式化版本保留在您的属性附近。

【讨论】:

  • 感谢您的回复。如果我的理解是正确的,我没有通过使用属性获得任何东西。我想知道MS如何实现这一点然后[DisplayFormat(DataFormatString="{0:C}")]
  • 而不是获取值,但是您可能只能通过反射来获取关联的属性而不是属性值,但这取决于您的应用程序。
  • 感谢您的示例。需要写入文件 280 列,并且每个字段都有不同的格式,并且由客户端规范决定。我认为与其为每个属性调用函数,不如创建更整洁的东西并使用属性和代码上的属性会更干净。从你所说的我似乎没有选择。
  • 问题是您至少需要知道属性名称才能访问其属性,因此对于您的特定情况可能会非常不舒服,但它也可以工作。对于其他版本的框架,您可以使用 lambda 表达式,但对于 C# 2.0,事情就相当复杂了。
  • 假设我想使用反射,我将如何在属性中使用你的函数?在 ToStringOverride 中?
【解决方案2】:

你需要反过来做。您的属性中不应该有任何逻辑,它应该简单地公开属性及其包含的信息(例如 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;
    }
}

【讨论】:

  • GetCustomAttributes().OfType 比使用 Attribute.GetCustomAttribute 慢,而且他没有 linq,因为它是 C# 2.0。
  • @SalvatorePreviti:代码看起来如何并不重要。属性保存其他类访问的元数据是概念,属性本身实际上不做任何事情。是的,您可以进行微优化(例如,将结果属性保存在某处,而不是每次都通过反射访问它),但这不是我的意思。此外,使用 .NET 2.0 并不能成为您使用 LINQ 的借口。你没听说过LINQBridge
猜你喜欢
  • 1970-01-01
  • 2012-05-05
  • 1970-01-01
  • 2012-10-04
  • 1970-01-01
  • 1970-01-01
  • 2011-01-24
  • 2011-05-02
  • 1970-01-01
相关资源
最近更新 更多