通过字符串从C#动态对象获取属性值(反射?)

91

假设我有一个动态变量:

dynamic d = *something*

现在,我为d创建属性,而d则来自于一个字符串数组:

string[] strarray = { 'property1','property2',..... }

我事先不知道属性名称。

在代码中,一旦创建了d并从数据库中提取了strarray,我如何获取值?

我想要获取d.property1,d.property2

我看到该对象有一个_dictionary内部字典,其中包含键和值,如何检索它们?


1
something 是一个 IDynamicMetaObjectProvider 吗? - SLaks
在调试器中检查 something 的运行时类型并查看其公共成员。 - SLaks
1
你能在运行时检查 d.GetType() 返回的结果吗? - Tomislav Markovski
这个SO答案展示了如何检索动态属性。 - Raymond Chen
可能是Loop DynamicObject properties的重复问题。 - nawfal
12个回答

129
我不知道是否有更优雅的方式来处理动态创建的对象,但是使用普通的反射应该可以解决问题。
var nameOfProperty = "property1";
var propertyInfo = myObject.GetType().GetProperty(nameOfProperty);
var value = propertyInfo.GetValue(myObject, null);
GetProperty 如果 myObject 的类型不包含具有该名称的公共属性,将返回 null

编辑:如果对象不是一个"常规"对象,而是实现了IDynamicMetaObjectProvider的某个东西,这种方法将无法工作。请查看下面的问题:


40

这将为您提供动态变量中定义的所有属性名称和值。

dynamic d = { // your code };
object o = d;
string[] propertyNames = o.GetType().GetProperties().Select(p => p.Name).ToArray();
foreach (var prop in propertyNames)
{
    object propValue = o.GetType().GetProperty(prop).GetValue(o, null);
}

1
这个对我来说非常有效,我无法实现动态类型,谢谢。 - Mrinal Kamboj
2
只有当d是静态类型时才有效。如果D是IDynamicMetaObjectProvider(例如JObject),它将返回错误的属性。例如,如果d = obj,则不会返回“x”,而是返回JObject上的原始属性。JObject obj = JObject.FromObject(new { x = 123 }); - Mike S

28
希望这能对你有所帮助:
public static object GetProperty(object o, string member)
{
    if(o == null) throw new ArgumentNullException("o");
    if(member == null) throw new ArgumentNullException("member");
    Type scope = o.GetType();
    IDynamicMetaObjectProvider provider = o as IDynamicMetaObjectProvider;
    if(provider != null)
    {
        ParameterExpression param = Expression.Parameter(typeof(object));
        DynamicMetaObject mobj = provider.GetMetaObject(param);
        GetMemberBinder binder = (GetMemberBinder)Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, member, scope, new CSharpArgumentInfo[]{CSharpArgumentInfo.Create(0, null)});
        DynamicMetaObject ret = mobj.BindGetMember(binder);
        BlockExpression final = Expression.Block(
            Expression.Label(CallSiteBinder.UpdateLabel),
            ret.Expression
        );
        LambdaExpression lambda = Expression.Lambda(final, param);
        Delegate del = lambda.Compile();
        return del.DynamicInvoke(o);
    }else{
        return o.GetType().GetProperty(member, BindingFlags.Public | BindingFlags.Instance).GetValue(o, null);
    }
}

@Ewerton,好久不见了。我看到它使用 System.Linq.Expressions 将动态 getter 绑定到调用站点,并将编译留给 LambdaExpression。我不知道这是从反编译的代码中获取的还是其他地方。 - IS4
你是一个大师! - momvart

9
使用以下代码获取动态对象属性的名称和值。
dynamic d = new { Property1= "Value1", Property2= "Value2"};

var properties = d.GetType().GetProperties();
foreach (var property in properties)
{
    var PropertyName=property.Name; 
//You get "Property1" as a result

  var PropetyValue=d.GetType().GetProperty(property.Name).GetValue(d, null); 
//You get "Value1" as a result

// you can use the PropertyName and Value here
 }

2
只有在基础类型为普通对象时才有效。它不适用于像 PSObject 这样的包装器对象。 - felixfbecker

6
string json = w.JSON;

var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new DynamicJsonConverter() });

DynamicJsonConverter.DynamicJsonObject obj = 
      (DynamicJsonConverter.DynamicJsonObject)serializer.Deserialize(json, typeof(object));

现在,obj._Dictionary 包含一个字典。完美!
这段代码必须与将JSON反序列化为C#动态对象?一起使用,并且需要将那里的代码中的_dictionary变量从“private readonly”更改为public。

5
如果d是由Newtonsoft创建的,您可以使用以下方法来读取属性名称和值:
    foreach (JProperty property in d)
    {
        DoSomething(property.Name, property.Value);
    }

4

你看到过 ExpandoObject 类吗?

直接从MSDN描述: "表示一个其成员可以在运行时被动态添加和删除的对象。"

使用它,你可以编写下面这样的代码:

dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
((IDictionary<String, Object>)employee).Remove("Name");

属性名称未知,因此这将无法工作。 - user3285954
代码可行(我在Visual Studio中进行了检查),因为员工实例是ExpandoObject,所以可以在运行时添加和删除属性(如MS官方文档中所述)。此代码完成了问题的要求。 - ADIMO
除了 ExpandoObject 之外,还有其他动态对象,例如 PSObject - felixfbecker
不,@ADIMO,它并没有。问题是如何访问动态对象的属性。但目前他不知道这些属性是什么。它们来自一个字符串数组。因此,他需要通过名称查找属性是否存在,然后从属性中获取值。 - gabriel.santos

3

使用属性(字符串)从动态对象中获取值数据。

var nameOfProperty = "chairs";
var propertyInfo = model.assets.GetType().GetField(nameOfProperty).GetValue(model.assets);

0

我知道这是一个旧问题,但我想分享我的解决方案: 这适用于动态和“非动态”数据:

var _RowData = mydata[RowIndex]; //<- Whole Row of Data
//Locate and Load the Field Property by Name:
var propertyInfo = System.ComponentModel.TypeDescriptor.
    GetProperties((object)_RowData ).   
    Find("field_name", true);

string FieldName = propertyInfo.Name;
object FieldValue = propertyInfo.GetValue(_dataRow);

使用Newtonsoft.Json将动态数据从JSON文件转换后进行测试。


-1
假设您在服务结果的Value中有一个匿名类型,其中包含errorCode类和ErrorMessage属性,并且需要获取ErrorMessage的值,可以使用dynamic在一行代码中获取它,如下所示:
var resVal = (dynamic)result.Value; var errMsg = resVal.GetType().GetProperty("errorCode").GetValue(resVal, null).ErrorMessage;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接