在 C# 中使用反射从字符串中获取属性值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1196991/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 10:38:18  来源:igfitidea点击:

Get property value from string using reflection in C#

c#reflectionproperties

提问by pedrofernandes

I am trying implement the Data transformation using Reflection1example in my code.

我正在尝试在我的代码中使用 Reflection 1示例实现数据转换

The GetSourceValuefunction has a switch comparing various types, but I want to remove these types and properties and have GetSourceValueget the value of the property using only a single string as the parameter. I want to pass a class and property in the string and resolve the value of the property.

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

Is this possible?

这可能吗?

1Web Archive version of original blog post

1原始博客文章的 Web Archive 版本

采纳答案by Ed S.

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

Of course, you will want to add validation and whatnot, but that is the gist of it.

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

回答by jheddings

How about something like this:

这样的事情怎么样:

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

        Type type = obj.GetType();
        PropertyInfo info = type.GetProperty(part);
        if (info == null) { return null; }

        obj = info.GetValue(obj, null);
    }
    return obj;
}

public static T GetPropValue<T>(this Object obj, String name) {
    Object retval = GetPropValue(obj, name);
    if (retval == null) { return default(T); }

    // throws InvalidCastException if types are incompatible
    return (T) retval;
}

This will allow you to descend into properties using a single string, like this:

这将允许您使用单个字符串下降到属性,如下所示:

DateTime now = DateTime.Now;
int min = GetPropValue<int>(now, "TimeOfDay.Minutes");
int hrs = now.GetPropValue<int>("TimeOfDay.Hours");

You can either use these methods as static methods or extensions.

您可以将这些方法用作静态方法或扩展。

回答by Guvante

You never mention what object you are inspecting, and since you are rejecting ones that reference a given object, I will assume you mean a static one.

您从未提及您正在检查的对象,并且由于您拒绝引用给定对象的对象,因此我假设您指的是静态对象。

using System.Reflection;
public object GetPropValue(string prop)
{
    int splitPoint = prop.LastIndexOf('.');
    Type type = Assembly.GetEntryAssembly().GetType(prop.Substring(0, splitPoint));
    object obj = null;
    return type.GetProperty(prop.Substring(splitPoint + 1)).GetValue(obj, null);
}

Note that I marked the object that is being inspected with the local variable obj. nullmeans static, otherwise set it to what you want. Also note that the GetEntryAssembly()is one of a few available methods to get the "running" assembly, you may want to play around with it if you are having a hard time loading the type.

请注意,我用局部变量标记了正在检查的对象objnull表示静态,否则将其设置为您想要的。另请注意,这GetEntryAssembly()是获取“正在运行”程序集的几种可用方法之一,如果您在加载类型时遇到困难,您可能想尝试一下。

回答by Fredou

What about using the CallByNameof the Microsoft.VisualBasicnamespace (Microsoft.VisualBasic.dll)? It uses reflection to get properties, fields, and methods of normal objects, COM objects, and even dynamic objects.

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

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

and then

进而

Versioned.CallByName(this, "method/function/prop name", CallType.Get).ToString();

回答by Kyle

Dim NewHandle As YourType = CType(Microsoft.VisualBasic.CallByName(ObjectThatContainsYourVariable, "YourVariableName", CallType), YourType)

回答by AlexD

Great answer by jheddings. I would like to improve it allowing referencing of aggregated arrays or collections of objects, so that propertyName could be property1.property2[X].property3:

jheddings 的精彩回答。我想改进它,允许引用聚合数组或对象集合,以便 propertyName 可以是 property1.property2[X].property3:

    public static object GetPropertyValue(object srcobj, string propertyName)
    {
        if (srcobj == null)
            return null;

        object obj = srcobj;

        // Split property name to parts (propertyName could be hierarchical, like obj.subobj.subobj.property
        string[] propertyNameParts = propertyName.Split('.');

        foreach (string propertyNamePart in propertyNameParts)
        {
            if (obj == null)    return null;

            // propertyNamePart could contain reference to specific 
            // element (by index) inside a collection
            if (!propertyNamePart.Contains("["))
            {
                PropertyInfo pi = obj.GetType().GetProperty(propertyNamePart);
                if (pi == null) return null;
                obj = pi.GetValue(obj, null);
            }
            else
            {   // propertyNamePart is areference to specific element 
                // (by index) inside a collection
                // like AggregatedCollection[123]
                //   get collection name and element index
                int indexStart = propertyNamePart.IndexOf("[")+1;
                string collectionPropertyName = propertyNamePart.Substring(0, indexStart-1);
                int collectionElementIndex = Int32.Parse(propertyNamePart.Substring(indexStart, propertyNamePart.Length-indexStart-1));
                //   get collection object
                PropertyInfo pi = obj.GetType().GetProperty(collectionPropertyName);
                if (pi == null) return null;
                object unknownCollection = pi.GetValue(obj, null);
                //   try to process the collection as array
                if (unknownCollection.GetType().IsArray)
                {
                    object[] collectionAsArray = unknownCollection as object[];
                    obj = collectionAsArray[collectionElementIndex];
                }
                else
                {
                    //   try to process the collection as IList
                    System.Collections.IList collectionAsList = unknownCollection as System.Collections.IList;
                    if (collectionAsList != null)
                    {
                        obj = collectionAsList[collectionElementIndex];
                    }
                    else
                    {
                        // ??? Unsupported collection type
                    }
                }
            }
        }

        return obj;
    }

回答by A Ghazal

Using PropertyInfo of the System.Reflectionnamespace. Reflection compiles just fine no matter what property we try to access. The error will come up during run-time.

使用System.Reflection命名空间的PropertyInfo 。无论我们尝试访问什么属性,反射都可以很好地编译。该错误将在运行时出现。

    public static object GetObjProperty(object obj, string property)
    {
        Type t = obj.GetType();
        PropertyInfo p = t.GetProperty("Location");
        Point location = (Point)p.GetValue(obj, null);
        return location;
    }

It works fine to get the Location property of an object

获取对象的 Location 属性效果很好

Label1.Text = GetObjProperty(button1, "Location").ToString();

We'll get the Location : {X=71,Y=27} We can also return location.X or location.Y on the same way.

我们将得到 Location : {X=71,Y=27} 我们也可以用同样的方式返回 location.X 或 location.Y。

回答by Budiantowang

shorter way ....

更短的方式....

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());

回答by Eduardo Cuomo

Add to any Class:

添加到任何Class

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

    public string Bar { get; set; }
}

Then, you can use as:

然后,您可以用作:

Foo f = new Foo();
// Set
f["Bar"] = "asdf";
// Get
string s = (string)f["Bar"];

回答by Recursor

Here is another way to find a nested property that doesn't require the string to tell you the nesting path. Credit to Ed S. for the single property method.

这是查找不需要字符串告诉您嵌套路径的嵌套属性的另一种方法。归功于 Ed S. 的单一属性方法。

    public static T FindNestedPropertyValue<T, N>(N model, string propName) {
        T retVal = default(T);
        bool found = false;

        PropertyInfo[] properties = typeof(N).GetProperties();

        foreach (PropertyInfo property in properties) {
            var currentProperty = property.GetValue(model, null);

            if (!found) {
                try {
                    retVal = GetPropValue<T>(currentProperty, propName);
                    found = true;
                } catch { }
            }
        }

        if (!found) {
            throw new Exception("Unable to find property: " + propName);
        }

        return retVal;
    }

        public static T GetPropValue<T>(object srcObject, string propName) {
        return (T)srcObject.GetType().GetProperty(propName).GetValue(srcObject, null);
    }