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

C# 使用反射从字符串获取属性值,c#,reflection,properties,C#,Reflection,Properties,我正在尝试在代码中实现1个示例 GetSourceValue函数有一个比较各种类型的开关,但我想删除这些类型和属性,让GetSourceValue仅使用单个字符串作为参数获取属性值。我想在字符串中传递一个类和属性,并解析该属性的值 这可能吗 一, 当然,您会希望添加验证之类的内容,但这就是它的要点。类似这样的内容如何: public static Object GetPropValue(this Object obj, String name) { foreach (String par

我正在尝试在代码中实现1个示例

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

这可能吗

一,


当然,您会希望添加验证之类的内容,但这就是它的要点。

类似这样的内容如何:

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;
}
DateTime now = DateTime.Now;
int min = GetPropValue<int>(now, "TimeOfDay.Minutes");
int hrs = now.GetPropValue<int>("TimeOfDay.Hours");
IResolver resolver = new Resolver();
var path = "Property1.Property2";
object result = r.Resolve(o, path); 
//=> "value"
公共静态对象GetPropValue(此对象对象,字符串名称){
foreach(name.Split('.')中的字符串部分){
如果(obj==null){返回null;}
Type Type=obj.GetType();
PropertyInfo=type.GetProperty(部分);
如果(info==null){returnnull;}
obj=info.GetValue(obj,空);
}
返回obj;
}
公共静态T GetPropValue(此对象对象对象,字符串名称){
Object retval=GetPropValue(obj,name);
如果(retval==null){返回默认值(T);}
//如果类型不兼容,则引发InvalidCastException
返回(T)返回;
}
这将允许您使用单个字符串进入属性,如下所示:

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;
}
DateTime now = DateTime.Now;
int min = GetPropValue<int>(now, "TimeOfDay.Minutes");
int hrs = now.GetPropValue<int>("TimeOfDay.Hours");
IResolver resolver = new Resolver();
var path = "Property1.Property2";
object result = r.Resolve(o, path); 
//=> "value"
DateTime now=DateTime.now;
int min=GetPropValue(现在是“TimeOfDay.Minutes”);
int hrs=now.GetPropValue(“TimeOfDay.Hours”);

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

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

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);
}
注意,我用局部变量
obj
标记了正在检查的对象
null
表示静态,否则将其设置为所需。还请注意,
GetEntryAssembly()
是获取“正在运行”程序集的几种可用方法之一,如果您在加载类型时遇到困难,您可能需要使用它。

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

using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;
然后

Versioned.CallByName(this, "method/function/prop name", CallType.Get).ToString();
。我希望通过允许引用聚合数组或对象集合来改进它,以便
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;
    }

使用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;
    }
它可以很好地获取对象的Location属性

Label1.Text = GetObjProperty(button1, "Location").ToString();
我们将得到位置:{X=71,Y=27} 我们也可以用同样的方法返回location.X或location.Y。

更短的方法

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

添加到任何
类中

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; }
}
然后,您可以将其用作:

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

下面是另一种查找嵌套属性的方法,它不需要字符串来告诉您嵌套路径。单一属性法的贷记给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);
    }
public static T FindNestedPropertyValue(N模型,字符串propName){
T retVal=默认值(T);
bool-found=false;
PropertyInfo[]properties=typeof(N).GetProperties();
foreach(属性中的PropertyInfo属性){
var currentProperty=property.GetValue(model,null);
如果(!找到){
试一试{
retVal=GetPropValue(currentProperty,propName);
发现=真;
}捕获{}
}
}
如果(!找到){
抛出新异常(“找不到属性:“+propName”);
}
返回返回;
}
公共静态T GetPropValue(对象srcObject,字符串propName){
返回(T)srcObject.GetType().GetProperty(propName).GetValue(srcObject,null);
}

以下代码是一种递归方法,用于显示对象实例中包含的所有属性名称和值的整个层次结构。此方法在此线程中使用上述AlexD的
GetPropertyValue()
答案的简化版本。多亏了这条讨论线索,我才知道如何做到这一点

例如,我使用此方法显示
WebService
响应中所有属性的爆炸或转储,方法如下:

propertyvalue\u通过执行(“响应”,响应,false)


关于“嵌套属性”讨论,如果使用以下选项,则可以避免所有反射内容:

var value = DataBinder.Eval(DateTime.Now, "TimeOfDay.Hours");
当然,您需要添加对
System.Web
程序集的引用,但这可能不是什么大问题。

公共静态列表GetProperties(对象项)//其中t:class
public static List<KeyValuePair<string, string>> GetProperties(object item) //where T : class
    {
        var result = new List<KeyValuePair<string, string>>();
        if (item != null)
        {
            var type = item.GetType();
            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var pi in properties)
            {
                var selfValue = type.GetProperty(pi.Name).GetValue(item, null);
                if (selfValue != null)
                {
                    result.Add(new KeyValuePair<string, string>(pi.Name, selfValue.ToString()));
                }
                else
                {
                    result.Add(new KeyValuePair<string, string>(pi.Name, null));
                }
            }
        }
        return result;
    }
{ var result=新列表(); 如果(项!=null) { var type=item.GetType(); var properties=type.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach(属性中的var pi) { var selfValue=type.GetProperty(pi.Name).GetValue(item,null); if(selfValue!=null) { 添加(新的KeyValuePair(pi.Name,selfValue.ToString()); } 其他的 { 添加(新的KeyValuePair(pi.Name,null)); } } } 返回结果; }
这是一种在列表中获取所有属性及其值的方法。

两人都对如何解析属性字符串给出了极好的答案。我想把我的也加入进来,因为我写了一个专门的库就是为了这个目的

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

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

var o = new { Property1 = new { Property2 = "value" } };
要获得
属性2
,可以这样做:

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;
}
DateTime now = DateTime.Now;
int min = GetPropValue<int>(now, "TimeOfDay.Minutes");
int hrs = now.GetPropValue<int>("TimeOfDay.Hours");
IResolver resolver = new Resolver();
var path = "Property1.Property2";
object result = r.Resolve(o, path); 
//=> "value"
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;
}
public class YourClass
{
    //Add below line in your class
    public object this[string propertyName] => GetType().GetProperty(propertyName)?.GetValue(this, null);
    public string SampleProperty { get; set; }
}

//And you can get value of any property like this.
var value = YourClass["SampleProperty"];
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;
var success = Reflector.Get(DateTime.Now, null, "Date.Year", out int value);
var getter = Reflector.CreateGetter<DateTime, int>("Date.Year", typeof(DateTime));
getter(DateTime.Now);
var getter = Reflector.CreateGetter<object, object>("Date.Year", typeof(DateTime));
getter(DateTime.Now);
public static T GetPropertyValue<T>(object sourceInstance, string targetPropertyName, bool throwExceptionIfNotExists = false)
{
    string errorMsg = null;

    try
    {
        if (sourceInstance == null || string.IsNullOrWhiteSpace(targetPropertyName))
        {
            errorMsg = $"Source object is null or property name is null or whitespace. '{targetPropertyName}'";
            Log.Warn(errorMsg);

            if (throwExceptionIfNotExists)
                throw new ArgumentException(errorMsg);
            else
                return default(T);
        }

        Type returnType = typeof(T);
        Type sourceType = sourceInstance.GetType();

        PropertyInfo propertyInfo = sourceType.GetProperty(targetPropertyName, returnType);
        if (propertyInfo == null)
        {
            errorMsg = $"Property name '{targetPropertyName}' of type '{returnType}' not found for source object of type '{sourceType}'";
            Log.Warn(errorMsg);

            if (throwExceptionIfNotExists)
                throw new ArgumentException(errorMsg);
            else
                return default(T);
        }

        return (T)propertyInfo.GetValue(sourceInstance, null);
    }
    catch(Exception ex)
    {
        errorMsg = $"Problem getting property name '{targetPropertyName}' from source instance.";
        Log.Error(errorMsg, ex);

        if (throwExceptionIfNotExists)
            throw;
    }

    return default(T);
}