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

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

这可能吗?

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


当前回答

虽然最初的问题是关于如何仅使用一个字符串作为参数来获取属性的值,但是在这里使用Expression而不是简单的字符串来确保调用者永远不会使用硬编码的属性名是很有意义的。下面是一行的用法:

public static class Utils
...
    public static TVal GetPropertyValue<T, TVal>(T t, Expression<Func<T, TVal>> x)
        => (TVal)((x.Body as MemberExpression)?.Member as PropertyInfo)!.GetValue(t);

...
    var val = Utils.GetPropertyValue(foo,  p => p.Bar);

下面是一个在可读性方面稍微好一点的错误处理版本:

public static TVal GetPropertyValue<T, TVal>(T t, Expression<Func<T, TVal>> x)
{
    var m = (x.Body as MemberExpression)?.Member;
    var p = m as PropertyInfo;

    if (null == p)
        throw new ArgumentException($"Unknown property: {typeof(T).Name}.{(m?.Name??"???")}");

    return (TVal)p.GetValue(t);
}

简而言之,您传递了一个读取属性的lambda表达式。lambda的主体(胖箭头右边的部分)是一个成员表达式,您可以从中获取成员名称并将其转换为PropertyInfo,前提是该成员实际上是一个Property,而不是(例如)一个方法。

在简短的版本中,null宽恕操作符——the !-告诉编译器PropertyInfo不会为空。这是一个很大的谎言,你将在运行时得到一个NullReferenceException。较长的版本提供了属性的名称(如果它设法获得该属性的话)。

PS:感谢Oleg G.为这段代码的初始版本:)

其他回答

public static TValue GetFieldValue<TValue>(this object instance, string name)
{
    var type = instance.GetType(); 
    var field = type.GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).FirstOrDefault(e => typeof(TValue).IsAssignableFrom(e.FieldType) && e.Name == name);
    return (TValue)field?.GetValue(instance);
}

public static TValue GetPropertyValue<TValue>(this object instance, string name)
{
    var type = instance.GetType();
    var field = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).FirstOrDefault(e => typeof(TValue).IsAssignableFrom(e.PropertyType) && e.Name == name);
    return (TValue)field?.GetValue(instance);
}

在. net Standard中调用的方法已经改变(从1.6开始)。我们还可以使用c# 6的空条件操作符。

using System.Reflection; 
public static object GetPropValue(object src, string propName)
{
    return src.GetType().GetRuntimeProperty(propName)?.GetValue(src);
}

如果我用Ed s的密码,我就

“ReflectionExtensions。由于其保护级别,GetProperty(Type, string)'不可访问

似乎GetProperty()在Xamarin.Forms中不可用。TargetFrameworkProfile是我的便携式类库中的Profile7。NET Framework 4.5, Windows 8, ASP。NET Core 1.0, Xamarin。Android, Xamarin的。Xamarin的iOS。iOS经典)。

现在我找到了一个可行的解决方案:

using System.Linq;
using System.Reflection;

public static object GetPropValue(object source, string propertyName)
{
    var property = source.GetType().GetRuntimeProperties().FirstOrDefault(p => string.Equals(p.Name, propertyName, StringComparison.OrdinalIgnoreCase));
    return property?.GetValue(source);
}

使用微软的CallByName怎么样?VisualBasic命名空间(Microsoft.VisualBasic.dll)?它使用反射来获取普通对象、COM对象甚至动态对象的属性、字段和方法。

using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;

然后

Versioned.CallByName(this, "method/function/prop name", CallType.Get).ToString();
Dim NewHandle As YourType = CType(Microsoft.VisualBasic.CallByName(ObjectThatContainsYourVariable, "YourVariableName", CallType), YourType)