我想使用字符串访问dynamic
c#属性的值:
dynamic d = new { value1 = "some", value2 = "random", value3 = "value" };
如果我只将“value2”作为字符串,我如何获得d.value2(“random”)的值?在javascript中,我可以使用d [“value2”]来访问值(“随机”),但我不知道如何使用c#和反射来执行此操作。我最接近的是:
d.GetType().GetProperty("value2")
...但我不知道如何从中获得实际价值。
一如既往,感谢您的帮助!
答案 0 :(得分:191)
获得PropertyInfo
(来自GetProperty
)后,您需要调用GetValue
并传入要从中获取值的实例。在你的情况下:
d.GetType().GetProperty("value2").GetValue(d, null);
答案 1 :(得分:36)
public static object GetProperty(object target, string name)
{
var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, name, target.GetType(), new[]{Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0,null)}));
return site.Target(site, target);
}
添加对Microsoft.CSharp的引用。也适用于动态类型和私有属性和字段。
编辑:虽然这种方法有效,但 Microsoft.VisualBasic.dll 程序集的方法快了近20倍:
public static object GetProperty(object target, string name)
{
return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get);
}
答案 2 :(得分:21)
Dynamitey是一个开源.net std
库,让你像dynamic
关键字一样调用它,但是使用字符串作为属性名,而不是编译器为你做,它最终成为equal to reflection speedwise(这并不像使用动态关键字那么快,但这是由于动态缓存的额外开销,编译器静态缓存)。
Dynamic.InvokeGet(d,"value2");
答案 3 :(得分:7)
在你要求动态对象的大部分时间里,你得到一个ExpandoObject(不在上面的问题的匿名但静态类型的例子中,但你提到JavaScript和我选择的JSON解析器JsonFx,生成一个,生成ExpandoObjects )。
如果你的动态实际上是一个ExpandoObject,你可以通过将它转换为IDictionary来避免反射,如http://msdn.microsoft.com/en-gb/library/system.dynamic.expandoobject.aspx所述。
一旦你转向IDictionary,你就可以访问有用的方法,如.Item和.ContainsKey
答案 4 :(得分:6)
获取适用于任何类型(包括setter
和getter
的属性的dynamic
和ExpandoObject
的最简单方法是使用FastMember
这也恰好是最快的方法(它使用Emit)。
您可以根据给定类型获得TypeAccessor
,也可以根据给定类型的实例获得ObjectAccessor
。
示例:
var staticData = new Test { Id = 1, Name = "France" };
var objAccessor = ObjectAccessor.Create(staticData);
objAccessor["Id"].Should().Be(1);
objAccessor["Name"].Should().Be("France");
var anonymous = new { Id = 2, Name = "Hilton" };
objAccessor = ObjectAccessor.Create(anonymous);
objAccessor["Id"].Should().Be(2);
objAccessor["Name"].Should().Be("Hilton");
dynamic expando = new ExpandoObject();
expando.Id = 3;
expando.Name = "Monica";
objAccessor = ObjectAccessor.Create(expando);
objAccessor["Id"].Should().Be(3);
objAccessor["Name"].Should().Be("Monica");
var typeAccessor = TypeAccessor.Create(staticData.GetType());
typeAccessor[staticData, "Id"].Should().Be(1);
typeAccessor[staticData, "Name"].Should().Be("France");
typeAccessor = TypeAccessor.Create(anonymous.GetType());
typeAccessor[anonymous, "Id"].Should().Be(2);
typeAccessor[anonymous, "Name"].Should().Be("Hilton");
typeAccessor = TypeAccessor.Create(expando.GetType());
((int)typeAccessor[expando, "Id"]).Should().Be(3);
((string)typeAccessor[expando, "Name"]).Should().Be("Monica");
答案 5 :(得分:4)
d.GetType()。的getProperty( “值2”)
返回一个PropertyInfo对象。
然后再做
propertyInfo.GetValue(d)
答案 6 :(得分:4)
这是我获得dinamic属性值的方式:
public dynamic Post(dynamic value)
{
try
{
if (value != null)
{
var valorCampos = "";
foreach (Newtonsoft.Json.Linq.JProperty item in value)
{
if (item.Name == "valorCampo")//property name
valorCampos = item.Value.ToString();
}
}
}
catch (Exception ex)
{
}
}
答案 7 :(得分:3)
GetProperty / GetValue不适用于Json数据,它总是生成一个空异常,但是,您可以尝试这种方法:
使用JsonConvert序列化您的对象:
var z = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(request));
然后直接将其转换回字符串:
var pn = (string)z["DynamicFieldName"];
它可以直接应用Convert.ToString(请求)[&#34; DynamicFieldName&#34;],但我还没有经过测试。
答案 8 :(得分:1)
在.Net core 3.1中,您可以这样尝试
d?.value2 , d?.value3
答案 9 :(得分:0)
从动态文档获取属性
当.GetType()
返回null
时,请尝试以下操作:
var keyValuePairs = ((System.Collections.Generic.IDictionary<string, object>)doc);
var val = keyValuePairs["propertyName"].ToObject<YourModel>;
答案 10 :(得分:0)
类似于接受的答案,您也可以尝试使用GetField
代替GetProperty
。
d.GetType().GetField("value2").GetValue(d);
取决于实际的Type
的实现方式,当GetProperty()不起作用甚至更快时,这可能会起作用。
答案 11 :(得分:0)
如果您有一个动态变量,例如 DapperRow,您可以先构建一个 ExpandoObject,然后将 Expando 转换为 IDictionary
辅助方法 ToExpandoObject:
public static ExpandoObject ToExpandoObject(object value)
{
IDictionary<string, object> dapperRowProperties = value as IDictionary<string, object>;
IDictionary<string, object> expando = new ExpandoObject();
if (dapperRowProperties == null)
{
return expando as ExpandoObject;
}
foreach (KeyValuePair<string, object> property in dapperRowProperties)
{
if (!expando.ContainsKey(property.Key))
{
expando.Add(property.Key, property.Value);
}
else
{
//prefix the colliding key with a random guid suffixed
expando.Add(property.Key + Guid.NewGuid().ToString("N"), property.Value);
}
}
return expando as ExpandoObject;
}
示例用法,我在示例中用粗体标记了让我们访问的转换,我用**字母标记了重要的位:
using (var transactionScope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
foreach (var dynamicParametersForItem in dynamicParametersForItems)
{
var idsAfterInsertion = (await connection.QueryAsync<object>(sql, dynamicParametersForItem)).ToList();
if (idsAfterInsertion != null && idsAfterInsertion.Any())
{
**var idAfterInsertionDict = (IDictionary<string, object>) ToExpandoObject(idsAfterInsertion.First());**
string firstColumnKey = columnKeys.Select(c => c.Key).First();
**object idAfterInsertionValue = idAfterInsertionDict[firstColumnKey];**
addedIds.Add(idAfterInsertionValue); //we do not support compound keys, only items with one key column. Perhaps later versions will return multiple ids per inserted row for compound keys, this must be tested.
}
}
}
在我的示例中,我在动态对象 DapperRow 中查找属性值,然后首先将 Dapper 行转换为 ExpandoObject 并将其转换为字典属性包,如此处其他答案中所示和所述。
我的示例代码是我正在处理的 Dapper 扩展的 InsertMany 方法,我想在批量插入后抓住这里的多个 id。