【问题标题】:Extension Method for Custom Attributes自定义属性的扩展方法
【发布时间】:2013-08-09 09:14:58
【问题描述】:

我正在开发一个 ASP.net MVC4 网站,并拥有模型和视图模型层。 由于某些原因我对 Model 和 ViewModel 中的几个属性有不同的名称

型号

public partial class Project
{
   public string Desc {get; set;}
}

查看模型

public class ProjectViewModel
{
   public string Description { get; set; }
}

现在在模型层,如果属性不同,我需要使用 ViewModel 名称。我正在考虑创建一个自定义属性,以便我可以在模型中拥有这样的东西:

public partial class Project
{
    [ViewModelPropertyName("Description")]
    public string Desc {get;set;}
}

并在模型层使用它作为

string.Format("ViewModel Property Name is {0}", this.Desc.ViewModelPropertyName())

我希望它是通用的,这样如果属性上没有ViewModelPropertyName 属性,那么它应该返回相同的属性名称,即如果Desc 属性没有属性,那么它应该只返回"Desc"

这是我尝试过的

public class ViewModelPropertyNameAttribute : System.Attribute
{
    #region Fields

    string viewModelPropertyName;

    #endregion

    #region Properties

    public string GetViewModelPropertyName()
    {
        return viewModelPropertyName;
    }

    #endregion

    #region Constructor

    public ViewModelPropertyNameAttribute(string propertyName)
    {
        this.viewModelPropertyName = propertyName;
    }

    #endregion
}

需要有关如何访问自定义属性的帮助

当前状态

    public static class ModelExtensionMethods
{
    public static string ViewModelPropertyName(this Object obj)
    {
        // ERROR: Cannot convert from 'object' to 'System.Reflect.Assembly'
        System.Attribute[] attrs = System.Attribute.GetCustomAttributes(obj);

        foreach (System.Attribute attr in attrs)
        {
            if (attr is ViewModelPropertyNameAttribute)
            {
                return ((ViewModelPropertyNameAttribute)attr).GetViewModelPropertyName();
            }
        }

        return string.Empty;
    }
}

但这有编译时错误:

【问题讨论】:

  • this.Desc.ViewModelPropertyName 必须是 this.Desc.GetViewModelPropertyName()。没有 extension property 这样的东西。

标签: c# c#-4.0 reflection extension-methods custom-attributes


【解决方案1】:

不幸的是,您无法通过反映属性本身的类型来获得用于装饰属性的属性。因此,我稍微修改了您的 ViewModelPropertyName(this object) 扩展方法以采用您所需属性的名称。

此方法现在将采用您希望获取其属性的属性的名称。如果属性存在,它将返回传递给其构造函数的值,另一方面,如果它不存在,它将简单地返回您传入的属性的名称。

public static class ModelExtensionMethods
{
    public static string ViewModelPropertyName(this object obj, string name)
    {
        var attributes = obj.GetType()
                            .GetCustomAttributes(true)
                            .OfType<MetadataTypeAttribute>()
                            .First()
                            .MetadataClassType 
                            .GetProperty(name)
                            .GetCustomAttributes(true);

        if (attributes.OfType<ViewModelPropertyNameAttribute>().Any())
        {
            return attributes.OfType<ViewModelPropertyNameAttribute>()
                             .First()
                             .GetViewModelPropertyName();
        }
        else
        {
            return name;
        } 
    }
}

您还可以定义以下类来测试这种新方法。

[MetadataType(typeof(TestClassMeta))]
class TestClass { }

class TestClassMeta
{
    [ViewModelPropertyName("TheName")]
    public string FirstName { get; set; }

    public string LastName { get; set; }
}

此外,从以下代码行可以看出,您的 ViewModelPropertyName(this object, string) 扩展方法现在将在您的 TestClass 实例上调用,而不是在财产本身。

class Program
{
    static void Main()
    {
        Console.WriteLine(new TestClass().ViewModelPropertyName("FirstName"));
        Console.WriteLine(new TestClass().ViewModelPropertyName("LastName"));

        Console.Read();
    }
}

【讨论】:

  • 感谢马里奥,但我在实施它时遇到了麻烦。我正在为模型使用元类或伙伴类,但 GetCustomAttributes 找不到 ViewModelPropertyName 属性
  • 我不确定你在那里有什么样的设置,但我已经编辑了我认为你正在使用的答案。 Extension 方法现在将首先从元类中获取属性,并在返回所需值之前在其属性中搜索其他属性。我还创建了一个由新属性修饰并包含所需属性的元类,而不是原来的 TestClass。
  • 我想再次感谢您提供的解决方案,并意识到我还需要在这方面学习多少。
  • 没问题,很高兴能帮上忙。鉴于我的其他大多数答案似乎都与反射有关,我还建议您浏览它们,看看您是否获得了一些对您有帮助的新信息。
猜你喜欢
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 2017-03-24
  • 2019-06-02
  • 2016-07-17
  • 2014-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多