GetSourceValue
函数具有比较各种类型的开关,但是我想删除这些类型和属性,并让GetSourceValue
获取属性的值仅使用单个字符串作为参数。我想在字符串中传递类和属性,并解析该属性的值。这可能吗?
1Web存档版本的原始博客文章
#1 楼
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
当然,您将需要添加验证等功能,但这就是要点。
#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");
您可以将这些方法用作静态方法或扩展。
评论
@FredJand很高兴您偶然发现了它!这些老帖子出现时总是令人惊讶。这有点含糊,所以我加了一些文字来解释它。我还改用这些作为扩展方法,并添加了泛型表单,因此在这里添加了它。
–珠宝
2012年11月8日15:23
为什么null保护区位于foreach中而不是上方?
–桑索斯
16年5月17日在11:03
@Santhos因为'obj'在foreach循环的主体中被重新定义,因此在每次迭代期间都会对其进行检查。
–珠宝
16年6月21日在16:13
有用,但在某些情况下可能会隐藏嵌套属性之一(使用'new'修饰符),它将抛出异常以查找重复的属性。跟踪最后一个属性类型并在嵌套属性上使用PropertyInfo.PropertyType而不是obj.GetType()将变得更加整洁,就像访问嵌套属性上的属性一样。
– Nullius
4月20日16:55
您可以在C#6及更高版本中使用nameof表达式,如下所示:在调用函数以消除魔术字符串并为这些调用添加编译时安全性时,在name参数上使用nameof(TimeOfDay.Minutes)。
–收获
5月30日4:50
#3 楼
添加到任何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"];
评论
@EduardoCuomo:可以在其中使用反射,这样您就不必知道类有哪些成员了?
–我们香蕉人
2015年8月20日在21:44
如果“酒吧”是一个对象,是否可以这样做?
–big_water
17年7月8日在17:49
@ big_water,SetValue和GetValue方法与Object一起使用。如果需要使用特定类型,则应强制转换GetValue的结果并强制转换该值以将其分配给SetValue
–爱德华多·库莫(Eduardo Cuomo)
17年3月3日在13:18
抱歉@OurManinBananas,我无法理解您的问题。你想让我做什么?
–爱德华多·库莫(Eduardo Cuomo)
17年11月3日在13:20
这种方法的名称是什么?
– Sahan Chinthaka
18年1月3日在14:19
#4 楼
如何使用CallByName
命名空间(Microsoft.VisualBasic
)的Microsoft.VisualBasic.dll
?它使用反射来获取常规对象,COM对象甚至动态对象的属性,字段和方法。using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;
然后
Versioned.CallByName(this, "method/function/prop name", CallType.Get).ToString();
评论
有趣的建议是,进一步检查证明它可以处理字段和属性,COM对象,甚至可以正确处理动态绑定!
– IllidanS4支持Monica
2014年11月2日17:31
我收到错误消息:找不到类型为“ MyType”的公共成员“ MyPropertyName”。
– vldmrrdjcc
19年4月4日在15:31
#5 楼
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;
}
评论
MasterList [0] [1]访问的列表列表如何?
–杰西·亚当(Jesse Adam)
2015年6月24日14:43在
as Array-> as object []也会导致Nullreference异常。对我有效的方法(不是最有效的方法),是将unknownCollection强制转换为IEnumerable,然后对结果使用ToArray()。小提琴
– Jeroen Jonkman
19-09-17在8:38
#6 楼
如果我使用Ed S中的代码。由于其保护级别,我无法访问'ReflectionExtensions.GetProperty(Type,string)'
似乎Q4312079q在Xamarin.Forms中不可用。我的可移植类库(.NET Framework 4.5,Windows 8,ASP.NET Core 1.0,Xamarin.Android,Xamarin.iOS,Xamarin.iOS Classic)中的
GetProperty()
是TargetFrameworkProfile
。现在我发现了解决方案:
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);
}
源
评论
只是可能的微小改进。将IF替换为下一个返回值:return property?.GetValue(source);
– Tomino
17-2-8在11:31
#7 楼
关于嵌套属性的讨论,如果使用DataBinder.Eval Method (Object, String)
,可以避免所有反射问题,如下所示:var value = DataBinder.Eval(DateTime.Now, "TimeOfDay.Hours");
当然,您需要添加一个引用
System.Web
组件,但这可能没什么大不了的。#8 楼
调用方法已在.NET Standard(自1.6版)中更改。我们也可以使用C#6的空条件运算符。using System.Reflection;
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetRuntimeProperty(propName)?.GetValue(src);
}
评论
准备使用?算子
– blfuentes
18年9月13日9:00
#9 楼
下面的方法对我来说很完美: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;
#10 楼
使用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。
#11 楼
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;
}
这是一种在列表中获取所有属性及其值的方法。
评论
为什么要这样做:在变量pi ==时键入type.GetProperty(pi.Name)?
–weston
16年1月6日在13:49
如果您使用的是c#6.0,请放弃if并执行selfValue?.ToString()否则,请摆脱if并使用selfValue == null?null:selfValue.ToString()
–weston
16年1月6日在13:50
另外List
–weston
16年1月6日于13:53
#12 楼
以下代码是一种递归方法,用于显示对象实例中包含的所有属性名称和值的整个层次结构。此方法在此线程中使用上面的AlexDGetPropertyValue()
答案的简化版本。多亏了这个讨论线程,我才能够弄清楚该怎么做!例如,我使用此方法通过调用
WebService
响应来显示爆炸或转储所有属性。方法如下:PropertyValues_byRecursion("Response", response, false);
public 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);
}
}
}
#13 楼
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);
}
#14 楼
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"];
#15 楼
Dim NewHandle As YourType = CType(Microsoft.VisualBasic.CallByName(ObjectThatContainsYourVariable, "YourVariableName", CallType), YourType)
#16 楼
这是查找嵌套属性的另一种方法,该属性不需要字符串即可告诉您嵌套路径。归功于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);
}
评论
最好检查Type.GetProperty是否返回null,而不是调用GetValue并在循环中抛出NullReferenceExceptions。
– Groo
16-2-11在8:22
#17 楼
您永远不会提及要检查的对象,并且由于您拒绝引用给定对象的对象,因此我假设您的意思是静态对象。使用局部变量
obj
标记了正在检查的对象。 null
表示静态,否则将其设置为所需的值。另请注意,GetEntryAssembly()
是获取“运行中”程序集的几种可用方法之一,如果在加载类型时遇到困难,则可能需要使用它。#18 楼
看看Heleonix.Reflection库。您可以通过路径获取/设置/调用成员,或者创建比反射更快的getter / setter(lambda编译为委托)。例如:var success = Reflector.Get(DateTime.Now, null, "Date.Year", out int value);
或者一次创建一个吸气剂并缓存以备重用(这具有更高的性能,但是如果中间成员为null则可能抛出NullReferenceException):
var getter = Reflector.CreateGetter<DateTime, int>("Date.Year", typeof(DateTime));
getter(DateTime.Now);
或者,如果您要创建不同吸气剂的
List<Action<object, object>>
,只需为编译的委托指定基本类型(类型转换将添加到编译的lambda中):var getter = Reflector.CreateGetter<object, object>("Date.Year", typeof(DateTime));
getter(DateTime.Now);
评论
如果可以在合理的时间内以5到10行的代码在自己的代码中实现,则永远不要使用3rd party库。
– Artem G
'18 Sep 5'在10:16
#19 楼
更短的方法....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());
#20 楼
jheddings和AlexD都就如何解析属性字符串写了出色的答案。我想把我的东西混在一起,因为我正是为此目的编写了一个专用库。Pather.CSharp的主要类是
Resolver
。默认情况下,它可以解析属性,数组和字典条目。因此,例如,如果您有这样的对象
var o = new { Property1 = new { Property2 = "value" } };
,要获取
Property2
,您可以这样操作:IResolver resolver = new Resolver();
var path = "Property1.Property2";
object result = r.Resolve(o, path);
//=> "value"
这是它可以解析的路径的最基本示例。如果您想了解它的其他功能或扩展方法,只需转到Github页面。
#21 楼
这是我的解决方案。它也可以与COM对象一起使用,并允许从COM对象访问集合/数组项。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;
}
#22 楼
这是我根据其他答案得到的。在使错误处理变得如此具体时有些过大的杀伤力。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);
}
评论
漂亮又简单!我将其设为通用:public static T GetPropertyValue
– Ohad Schneider
15年5月30日在10:29
优化可以消除出现空异常的风险,例如:“ src.GetType()。GetProperty(propName)?. GetValue(src,null);”。 ;)。
–shA.t
18/12/12在7:10
@ shA.t:我认为这是个坏主意。如何区分现有属性的空值或根本没有属性?我非常希望立即知道我发送的属性名称不正确。这不是生产代码,但是更好的改进是引发更具体的异常(例如,检查GetProperty上的null并抛出PropertyNotFoundException或其他东西(如果为null)。)
– Ed S.
18/12/15在18:22
万一您的属性确实是一个字段而不是一个属性(例如我的;)),则使用GetField而不是GetProperty
–克里斯托弗·K。
7月10日13:21