本文介绍了比较对象与C#中PropertyInfo.GetValue结果的最简单方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  • C是某些类的具有DisplayNameAttribute的属性成员
  • GetDisplayName方法返回指定属性成员的DisplayNameAttribute参数
  • .net3.5,Unity3D

我的问题是实现确实是多余的,因为方法SequenceEqual需要指定的类型参数,因此我应该为每种可能的属性类型实现IF代码块.有反射黑魔法可以使我的代码更清晰吗?

My problem is the implementation is really redundant because method SequenceEqual needs specified type parameters, so I should implement IF code block for each possible property type. Is there any reflection black magic can make my code cleaner?

public class C
{
    [DisplayName("M1")]
    public List<string> M1 { get; set; }
    [DisplayName("M2")]
    public List<string> M2 { get; set; }
    [DisplayName("M3")]
    public string M3 { get; set; }
    [DisplayName("M4")]
    public List<int> M4 { get; set; }
    //There can be many property members with different type
    //M5
    //...
    //...
    //M99
}

public void GetCMemberDisplayName()
{
    var c = new C
    {
        M1 = new List<string> {"a"},
        M2 = new List<string>(),
        M3 = "b",
        M4 = new List<int>()
    };
    var nameOfM1 = GetDisplayName(c, c.M1);//"M1"
    var nameOfM2 = GetDisplayName(c, c.M2);//"M2"
    var nameOfM3 = GetDisplayName(c, c.M3);//"M3"
}

//EDIT, add another situation, instance and its property member could be input parameters
public string AnotherGetMemberDisplay(object instance, object member)
{
    return GetDisplayName(instance, member);
}

private static string GetDisplayName(object instance, object member)
{
    var propertyInfos = instance.GetType()
        .GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
                        | BindingFlags.GetField | BindingFlags.GetProperty)
        .FindAll(pi => pi.IsDefined(typeof(DisplayNameAttribute), true));


    foreach (var propertyInfo in propertyInfos)
    {
        var value = propertyInfo.GetValue(instance, null);

        //Very nasty code below, need implement all IF code for each type of property member
        if (member.GetType() == typeof(List<string>) && value.GetType() == typeof(List<string>))
        {
            if ((value as List<string>).SequenceEqual(member as List<string>))
            {
                return (propertyInfo.GetCustomAttributes(true).ToList()
                    .Find(a => (a as DisplayNameAttribute) != null) as DisplayNameAttribute)
                    .DisplayName;
            }
        }
        else if (member.GetType() == typeof(List<int>) && value.GetType() == typeof(List<int>))
        {
            if ((value as List<int>).SequenceEqual(member as List<int>))
            {
                return (propertyInfo.GetCustomAttributes(true).ToList()
                    .Find(a => (a as DisplayNameAttribute) != null) as DisplayNameAttribute)
                    .DisplayName;
            }
        }
        else
        {
            if (value == member)
            {
                return (propertyInfo.GetCustomAttributes(true).ToList()
                    .Find(a => (a as DisplayNameAttribute) != null) as DisplayNameAttribute)
                    .DisplayName;
            }
        }


    }

    throw new Exception("No DisplayNameAttributes Applied.");
}

推荐答案

我建议按照以下方式实现一种方法,以获取所需属性的MemberInfo:

I would suggest implementing a method along these lines to get the MemberInfo for the desired property:

public MemberInfo GetMemberInfo<T>(Expression<Func<T>> memberLambda)
{
    var memberExpression = memberLambda.Body as MemberExpression;

    if (memberExpression == null)
    {
        throw new ArgumentException("You must pass a lambda of the form: '() => Class.Member' or '() => object.Member'");
    }

    return memberExpression.Member;
}

(源自asker的解决方案,在这里:以字符串形式获取属性名称)

(derived from asker's solution here: Get name of property as a string)

然后获取属性值就这么简单:

Then acquiring the attribute value is as simple as this:

public void GetCMemberDisplayName()
{
    var c = new C
    {
        M1 = new List<string> {"a"},
    };

    var m1MemberInfo = GetMemberInfo(() => c.M1);
    var nameOfM1 = GetDisplayName(m1MemberInfo);
}

private string GetDisplayName(MemberInfo memberInfo)
{
    var displayNameAttribute = memberInfo.GetCustomAttribute(typeof(DisplayNameAttribute));

    if (displayNameAttribute != null)
    {
        return displayNameAttribute.DisplayName;
    }
    else
    {
        throw new Exception("No DisplayNameAttributes Applied.");
    }
}

我避免使用C#6代码,因为您最初的帖子被标记为Unity3D,该代码使用了当前不支持C#6的编译器.如果您使用的是支持C#6的编译器,则过程为更简单(您不再需要GetMemberInfo方法):

I've avoided using C# 6 code, as you originally had your post tagged as Unity3D, which uses a compiler that currently doesn't support C# 6. If you're using a compiler that does support it, the process is simpler (you no longer need the GetMemberInfo method):

public void GetCMemberDisplayName()
    {
        var c = new C
        {
            M1 = new List<string> {"a"},
        };

        var nameOfM1 = GetDisplayName(typeof(C), nameof(c.M1));
    }


private static string GetDisplayName(Type ownerType, string propertyName)
{
    var propertyInfo = ownerType.GetProperty(propertyName);

    var displayNameAttribute = propertyInfo.GetCustomAttribute(typeof(DisplayNameAttribute));

    if (displayNameAttribute != null)
    {
        return displayNameAttribute.DisplayName;
    }
    else
    {
        throw new Exception("No DisplayNameAttributes Applied.");
    }
}

这篇关于比较对象与C#中PropertyInfo.GetValue结果的最简单方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 17:36