使用C#中的反射从字符串获取属性值 |
您所在的位置:网站首页 › selfvalue › 使用C#中的反射从字符串获取属性值 |
我正在尝试在代码中使用Reflection1示例实现数据转换。 GetSourceValue函数有一个比较各种类型的开关,但是我想删除这些类型和属性,并让GetSourceValue只使用一个字符串作为参数来获取属性的值。我想在字符串中传递一个类和属性,并解析该属性的值。 这有可能吗? 1Web Archive version of Original Blog Post 1234 public static object GetPropValue(object src, string propName) { return src.GetType().GetProperty(propName).GetValue(src, null); }当然,您需要添加验证和其他内容,但这就是其中的要点。 相关讨论 是的,我知道我可以像你说的那样使用。但我不想传递SRC对象。我只想传递一个名为"class1.prop1"的字符串,并给我class1类的prop1值。 你在问题"我要通过班级"中问的,我想这是"对象"而不是"班级",因为"班级"没有意义。你为什么要投反对票?你不知道如何修改这个代码来使用"this"吗?它是类的静态属性吗?你需要更具体一些,这是正确的答案。 src.gettype().getproperty(propname).getValue(src,null)为嵌套对象返回空值。我的意思是像school.employee.name在本例中是school.getType().getProperty(employee.name).getValue(school,空) @穆拉里:因为那是错误的。您需要先获取Employee属性的值,然后再次执行相同的操作。 @我正在处理一个需要将一些值(属性)移动到同一类型的其他对象的需求。我还得到字符串列表,其中包含我需要复制该值的属性名。例如"name"、"employee.name"等。我需要做一个反射以从obja获取这些属性值,并将其设置为objb。我有办法处理吗?到目前为止,我编写了一个通用方法来获取给定属性名的属性值。代码正好低于jheddings answer的代码。我所需要的只是如何用obja的新值设置另一个对象(同一类型,objb)?有什么想法或帮助吗? @艾德,不起作用。我错过了什么? @汤姆和第225;?扎托:它不起作用,因为test不是一个属性,而是一个字段。使用属性或使用适当的反射调用获取字段值。只是好奇,你对这个答案投了反对票吗?如果是这样,也许你应该重新考虑。 @是的,对不起。我完全不知道在C中有一个叫做field的东西,而不是财产。我的投票被锁定了。我能做什么? @汤姆和第225;?扎托:没关系,投反对票也没什么大不了的,不过在将来投反对票之前,要确定你知道你在说什么。 又好又简单!不过,我会把它变成通用的:public static T GetPropertyValue(object obj, string propName) { return (T)obj.GetType().GetProperty(propName).GetValue(obj, null); }。 您应该包括一个示例,不清楚SRC应该包含什么。 @罗尔斯:嗯?src是一个对象…GetType是在对象上定义的…你想做什么就做什么。 对不起,我知道怎么用。我只是觉得如果你用一个如何使用函数的例子来展示更多的行,可能会更整洁一些,因为它可能不会立即清晰。 @滚动,你可以在任何类型的对象上执行这个操作。 优化可以消除这样的空异常风险:"src.GetType().GetProperty(propName)?.GetValue(src, null);"。 @夏:我觉得这是个坏主意。如何区分现有属性的空值或根本没有属性?我宁愿立刻知道我寄来了一个不好的地名。这不是生产代码,但更好的改进是抛出更具体的异常(例如,检查GetProperty上的空值,如果为空则抛出PropertyNotFoundException或其他东西)。像这样的怎么样: 1234567891011121314151617181920public 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(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; }这将允许您使用单个字符串下降到属性中,如下所示: 123DateTime now = DateTime.Now; int min = GetPropValue(now,"TimeOfDay.Minutes"); int hrs = now.GetPropValue("TimeOfDay.Hours");您可以将这些方法用作静态方法或扩展。 相关讨论 @Fredjand很高兴你偶然发现了它!当这些旧的帖子出现时总是令人惊讶。它有点模糊,所以我加了一点文字来解释它。我还使用这些作为扩展方法,并添加了一个泛型表单,所以我在这里添加了它。 为什么前臂中的空保护不在上面? @Santhos因为在foreach循环体中重新定义了"obj",所以在每次迭代中都会检查它。添加到任何Class中: 12345678910public 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; } }然后,您可以将其用作: 12345Foo f = new Foo(); // Set f["Bar"] ="asdf"; // Get string s = (string)f["Bar"]; 相关讨论 @爱德华多科莫:有没有可能用反射来处理这个问题,这样你就不需要知道这个班有哪些成员? 如果"bar"是一个对象,是否可以这样做? 使用字符串键使对象像字典一样!!!!令人惊叹的 @大水:SetValue和GetValue方法与Object一起工作。如果需要使用特定类型,则应强制转换GetValue的结果,并强制转换值以将其与SetValue赋值。 抱歉,我不能理解你的问题。你想做什么? 此类型方法的名称是什么….?使用Microsoft.VisualBasic名称空间(Microsoft.VisualBasic.dll)的CallByName怎么样?它使用反射来获取普通对象、COM对象甚至动态对象的属性、字段和方法。 12using Microsoft.VisualBasic; using Microsoft.VisualBasic.CompilerServices;然后 1Versioned.CallByName(this,"method/function/prop name", CallType.Get).ToString(); 相关讨论 有意思的建议,进一步的检查证明,它既可以处理字段和属性,也可以处理COM对象,甚至可以正确处理动态绑定! 这应该是所有人的正确答案:)杰丁斯的回答很好。我希望改进它,允许引用聚合数组或对象集合,以便propertyname可以是property1.property2[x].property3: 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 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; } 相关讨论 主列表[0][1]访问的列表列表怎么样?如果我使用Ed S的代码,我会 'ReflectionExtensions.GetProperty(Type, string)' is inaccessible due to its protection level 似乎没有Xamarin.forms提供GetProperty()。TargetFrameworkProfile是我的可移植类库(.NET Framework 4.5、Windows 8、ASP.NET Core 1.0、Xamarin.android、Xamarin.ios、Xamarin.ios classic)中的Profile7。 现在我找到了一个可行的解决方案: 12345678using 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); }来源 相关讨论 只是一个小小的改进。将if和next返回替换为:返回属性?.getvalue(源);关于嵌套属性的讨论,如果使用DataBinder.Eval Method (Object, String)如下所示,则可以避免所有反射内容: 1var value = DataBinder.Eval(DateTime.Now,"TimeOfDay.Hours");当然,您需要添加对System.Web组件的引用,但这可能不是什么大问题。 .NET标准中要调用的方法已更改(从1.6开始)。我们还可以使用C 6的空条件运算符。 12345using System.Reflection; public static object GetPropValue(object src, string propName) { return src.GetType().GetRuntimeProperty(propName)?.GetValue(src); } 相关讨论 用于使用? operator。使用System.Reflection命名空间的PropertyInfo。无论我们试图访问什么属性,反射编译都很好。运行时出错。 1234567 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; }它可以很好地获取对象的位置属性 1Label1.Text = GetObjProperty(button1,"Location").ToString();我们会得到位置:x=71,y=27我们也可以用同样的方法返回location.x或location.y。 12345678910111213141516171819202122public static List GetProperties(object item) //where T : class { var result = new List(); 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(pi.Name, selfValue.ToString())); } else { result.Add(new KeyValuePair(pi.Name, null)); } } } return result; }这是一种在列表中获取所有属性及其值的方法。 相关讨论 为什么要这样做:当它对变量pi==时,type.GetProperty(pi.Name)? 如果你使用c 6.0,去掉if,做selfValue?.ToString(),否则去掉if,使用selfValue==null?null:selfValue.ToString()。 还有一个List的列表是奇数,使用字典Dictionary。 123456789public 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"];你从来没有提到你要检查的对象,而且由于你拒绝了引用一个给定对象的对象,我假设你是指一个静态对象。 12345678using 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()是获得"正在运行"程序集的几种可用方法之一,如果在加载类型时遇到困难,您可能希望使用它。 下面的代码是一个递归方法,用于显示对象实例中包含的所有属性名和值的整个层次结构。这个方法在这个线程中使用了上面Alexd的GetPropertyValue()答案的简化版本。多亏了这条讨论线,我才知道该怎么做! 例如,我使用此方法通过调用以下方法来显示WebService响应中所有属性的爆炸或转储: PropertyValues_byRecursion("Response", response, false); 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990public static object GetPropertyValue(object srcObj, string propertyName) { if (srcObj == null) { return null; } PropertyInfo pi = srcObj.GetType().GetProperty(propertyName.Replace("[]","")); if (pi == null) { return null; } return pi.GetValue(srcObj); } public static void PropertyValues_byRecursion(string parentPath, object parentObj, bool showNullValues) { /// Processes all of the objects contained in the parent object. /// If an object has a Property Value, then the value is written to the Console /// Else if the object is a container, then this method is called recursively /// using the current path and current object as parameters // Note: If you do not want to see null values, set showNullValues = false foreach (PropertyInfo pi in parentObj.GetType().GetTypeInfo().GetProperties()) { // Build the current object property's namespace path. // Recursion extends this to be the property's full namespace path. string currentPath = parentPath +"." + pi.Name; // Get the selected property's value as an object object myPropertyValue = GetPropertyValue(parentObj, pi.Name); if (myPropertyValue == null) { // Instance of Property does not exist if (showNullValues) { Console.WriteLine(currentPath +" = null"); // Note: If you are replacing these Console.Write... methods callback methods, // consider passing DBNull.Value instead of null in any method object parameters. } } else if (myPropertyValue.GetType().IsArray) { // myPropertyValue is an object instance of an Array of business objects. // Initialize an array index variable so we can show NamespacePath[idx] in the results. int idx = 0; foreach (object business in (Array)myPropertyValue) { if (business == null) { // Instance of Property does not exist // Not sure if this is possible in this context. if (showNullValues) { Console.WriteLine(currentPath +"[" + idx.ToString() +"]" +" = null"); } } else if (business.GetType().IsArray) { // myPropertyValue[idx] is another Array! // Let recursion process it. PropertyValues_byRecursion(currentPath +"[" + idx.ToString() +"]", business, showNullValues); } else if (business.GetType().IsSealed) { // Display the Full Property Path and its Value Console.WriteLine(currentPath +"[" + idx.ToString() +"] =" + business.ToString()); } else { // Unsealed Type Properties can contain child objects. // Recurse into my property value object to process its properties and child objects. PropertyValues_byRecursion(currentPath +"[" + idx.ToString() +"]", business, showNullValues); } idx++; } } else if (myPropertyValue.GetType().IsSealed) { // myPropertyValue is a simple value Console.WriteLine(currentPath +" =" + myPropertyValue.ToString()); } else { // Unsealed Type Properties can contain child objects. // Recurse into my property value object to process its properties and child objects. PropertyValues_byRecursion(currentPath, myPropertyValue, showNullValues); } } } 12345678910111213public static TValue GetFieldValue(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(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); }这是另一种查找嵌套属性的方法,不需要字符串来告诉您嵌套路径。对于单属性方法,请归功于Ed S.。 123456789101112131415161718192021222324252627 public static T FindNestedPropertyValue(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(currentProperty, propName); found = true; } catch { } } } if (!found) { throw new Exception("Unable to find property:" + propName); } return retVal; } public static T GetPropValue(object srcObject, string propName) { return (T)srcObject.GetType().GetProperty(propName).GetValue(srcObject, null); } 相关讨论 最好检查Type.GetProperty是否返回null,而不是调用GetValue,并在循环中抛出NullReferenceException。更短的路…… 12345var 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());Jheddings和Alexd都写了关于如何解析属性字符串的很好的答案。我想把我的混合,因为我写了一个专门的图书馆正是为了这个目的。 探路者。CSharp的主要阶级是Resolver。默认情况下,它可以解析属性、数组和字典条目。 例如,如果有这样的对象 1var o = new { Property1 = new { Property2 ="value" } };想要得到Property2,你可以这样做: 1234IResolver resolver = new Resolver(); var path ="Property1.Property2"; object result = r.Resolve(o, path); //=>"value"这是最基本的路径示例。如果你想知道它还能做些什么,或者你如何扩展它,就直接进入它的Github页面。 1Dim NewHandle As YourType = CType(Microsoft.VisualBasic.CallByName(ObjectThatContainsYourVariable,"YourVariableName", CallType), YourType)以下方法非常适合我: 123456789class 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); } } }要获取属性值: 123MyClass t1 = new MyClass(); ... string value = t1["prop1"].ToString();要设置属性值: 1t1["prop1"] = value;看看Heleonix.Reflection库。您可以通过路径获取/设置/调用成员,或者创建一个比反射更快的getter/setter(编译为委托的lambda)。例如: 1var success = Reflector.Get(DateTime.Now, null,"Date.Year", out int value);或者创建一次getter并缓存以供重用(这更具性能,但如果中间成员为空,则可能引发NullReferenceException): 12var getter = Reflector.CreateGetter("Date.Year", typeof(DateTime)); getter(DateTime.Now);或者,如果要创建不同getter的List>,只需为已编译委托指定基类型(类型转换将添加到已编译的lambda中): 12var getter = Reflector.CreateGetter("Date.Year", typeof(DateTime)); getter(DateTime.Now); 相关讨论 如果您可以在合理的时间内用5-10行代码在自己的代码中实现,就不要使用第三方libs。这是我根据其他答案得到的结果。对错误处理的具体化有点过分。 123456789101112131415161718192021222324252627282930313233343536373839404142434445public static T GetPropertyValue(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); } 相关讨论 尝试添加一些代码注释这是我的解决方案。它还与COM对象一起工作,并允许从COM对象访问集合/数组项。 1234567891011121314151617181920212223242526272829303132333435363738394041424344public 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 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |