我试图在我的代码中使用Reflection1示例实现数据转换。

GetSourceValue函数有一个比较各种类型的开关,但我想删除这些类型和属性,并让GetSourceValue只使用一个字符串作为参数来获取属性的值。我想在字符串中传递一个类和属性,并解析属性的值。

这可能吗?

1原始博客文章的Web存档版本


当前回答

jheddings和AlexD都写了关于如何解析属性字符串的出色答案。我想把我的库也加入其中,因为我专门为此编写了一个库。

路径。CSharp的主类是Resolver。默认情况下,它可以解析属性、数组和字典条目。

举个例子,如果你有一个这样的物体

var o = new { Property1 = new { Property2 = "value" } };

想要获得Property2,你可以这样做:

IResolver resolver = new Resolver();
var path = "Property1.Property2";
object result = r.Resolve(o, path); 
//=> "value"

这是它可以解析的路径的最基本示例。如果你想看看它还能做什么,或者你可以如何扩展它,只需前往它的Github页面。

其他回答

 public static object GetPropValue(object src, string propName)
 {
     return src.GetType().GetProperty(propName).GetValue(src, null);
 }

当然,您会想要添加验证和诸如此类的东西,但这就是它的要点。

看看Heleonix。反映图书馆。你可以通过路径获取/设置/调用成员,或者创建一个getter/setter (lambda编译成委托),这比反射更快。例如:

var success = Reflector.Get(DateTime.Now, null, "Date.Year", out int value);

或者只创建一个getter并缓存以供重用(这样性能更好,但如果中间成员为空可能会抛出NullReferenceException):

var getter = Reflector.CreateGetter<DateTime, int>("Date.Year", typeof(DateTime));
getter(DateTime.Now);

或者如果你想创建一个List<Action<object, object>>的不同getter,只需要为已编译的委托指定基本类型(类型转换将被添加到已编译的lambdas中):

var getter = Reflector.CreateGetter<object, object>("Date.Year", typeof(DateTime));
getter(DateTime.Now);

捷径....

var a = new Test { Id = 1 , Name = "A" , date = DateTime.Now};
var b = new Test { Id = 1 , Name = "AXXX", date = DateTime.Now };

var compare = string.Join("",a.GetType().GetProperties().Select(x => x.GetValue(a)).ToArray())==
              string.Join("",b.GetType().GetProperties().Select(x => x.GetValue(b)).ToArray());

下面的方法非常适合我:

class MyClass {
    public string prop1 { set; get; }

    public object this[string propertyName]
    {
        get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
        set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
    }
}

获取属性值:

MyClass t1 = new MyClass();
...
string value = t1["prop1"].ToString();

设置属性值。

t1["prop1"] = value;

这是我的解决方案。它也适用于COM对象,并允许从COM对象访问集合/数组项。

public static object GetPropValue(this object obj, string name)
{
    foreach (string part in name.Split('.'))
    {
        if (obj == null) { return null; }

        Type type = obj.GetType();
        if (type.Name == "__ComObject")
        {
            if (part.Contains('['))
            {
                string partWithoundIndex = part;
                int index = ParseIndexFromPropertyName(ref partWithoundIndex);
                obj = Versioned.CallByName(obj, partWithoundIndex, CallType.Get, index);
            }
            else
            {
                obj = Versioned.CallByName(obj, part, CallType.Get);
            }
        }
        else
        {
            PropertyInfo info = type.GetProperty(part);
            if (info == null) { return null; }
            obj = info.GetValue(obj, null);
        }
    }
    return obj;
}

private static int ParseIndexFromPropertyName(ref string name)
{
    int index = -1;
    int s = name.IndexOf('[') + 1;
    int e = name.IndexOf(']');
    if (e < s)
    {
        throw new ArgumentException();
    }
    string tmp = name.Substring(s, e - s);
    index = Convert.ToInt32(tmp);
    name = name.Substring(0, s - 1);
    return index;
}