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

  显示原文与译文双语对照的内容

使用反射在 ,我在试实现数据转换 1 代码中的示例。

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

这可能吗?

1站点存档版本的原始博客标题

时间:


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

当然,你需要添加验证和其他内容,但这是它的要点。

这样的东西怎么样:


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

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

那么,使用了 CallByNameMicrosoft.VisualBasic 命名空间( Microsoft.VisualBasic.dll )的? 它使用反射来获取普通对象,com对象和甚至动态对象的属性,字段和方法。


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

然后


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

较大的回答通过 jheddings 。我想改进它允许引用的聚合级的对象的数组或者集合,这样,属性名可能是二者 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 Array[];
 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;
 }

添加到任何 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; }
}

然后,你可以使用:


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

你从不提到你正在检查的对象,因为你拒绝那些引用了给定对象的对象,我将假设你是一个静态的对象。


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标记了正在检查的对象。 空表示静态,否则将它的设置为你想要的。 还要注意,GetEntryAssembly() 是获取"正在运行"程序集的几种可用方法之一,如果你有困难的时间加载类型,你可能需要使用它。

使用 System.Reflection 命名空间的PropertyInfo 。 无论我们尝试访问什么属性,反射都很好。 错误将在run-time期间出现。


 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;
 }

获取对象的位置属性很好


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

我们将获得位置:{X=71,Y=27} 也可以同样的方式返回 location.X 或者 location.Y 。

下面是查找嵌套属性的另一种方法,它不要求字符串告诉你嵌套路径。 对Ed的信用。对于单一属性方法。


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

更短的方式。。


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

...