我想将匿名对象作为方法的参数,然后遍历其属性以将每个属性/值添加到动态ExpandoObject
中。
所以我需要的是从
new { Prop1 = "first value", Prop2 = SomeObjectInstance, Prop3 = 1234 }
要知道每个属性的名称和值,并能够将它们添加到ExpandoObject
中。
我该如何做到这一点?
附注:这将在我的许多单元测试中完成(我正在使用它来重构设置中的许多垃圾),因此性能在某种程度上是相关的。我对反射的了解还不够多,但据我所知,它的性能相当重,所以如果可能的话,我宁愿避免它……
后续问题:正如我所说的,我将这个匿名对象作为一个方法的参数。我应该在方法的签名中使用什么数据类型?如果我使用object
,是否所有属性都可用
发布于 2010-04-08 01:26:40
foreach(var prop in myVar.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
Console.WriteLine("Name: {0}, Value: {1}",prop.Name, prop.GetValue(myVar,null));
}
发布于 2013-07-24 08:08:45
考虑匿名对象以获得它的属性名称和值,然后利用ExpandoObject实际上是一个字典来填充它。下面是一个表示为单元测试的示例:
[TestMethod]
public void ShouldBeAbleToConvertAnAnonymousObjectToAnExpandoObject()
{
var additionalViewData = new {id = "myControlId", css = "hide well"};
dynamic result = new ExpandoObject();
var dict = (IDictionary<string, object>)result;
foreach (PropertyInfo propertyInfo in additionalViewData.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
dict[propertyInfo.Name] = propertyInfo.GetValue(additionalViewData, null);
}
Assert.AreEqual(result.id, "myControlId");
Assert.AreEqual(result.css, "hide well");
}
发布于 2010-04-08 01:48:55
另一种方法是使用DynamicObject
而不是ExpandoObject
,这样当您实际尝试从另一个对象访问属性时,才会有进行反射的开销。
public class DynamicForwarder : DynamicObject
{
private object _target;
public DynamicForwarder(object target)
{
_target = target;
}
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
var prop = _target.GetType().GetProperty(binder.Name);
if (prop == null)
{
result = null;
return false;
}
result = prop.GetValue(_target, null);
return true;
}
}
现在,只有当您实际尝试通过动态get访问属性时,它才会进行反射。缺点是,如果您重复访问相同的属性,它每次都必须进行反射。因此,您可以缓存结果:
public class DynamicForwarder : DynamicObject
{
private object _target;
private Dictionary<string, object> _cache = new Dictionary<string, object>();
public DynamicForwarder(object target)
{
_target = target;
}
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
// check the cache first
if (_cache.TryGetValue(binder.Name, out result))
return true;
var prop = _target.GetType().GetProperty(binder.Name);
if (prop == null)
{
result = null;
return false;
}
result = prop.GetValue(_target, null);
_cache.Add(binder.Name, result); // <-------- insert into cache
return true;
}
}
您可以支持存储目标对象列表以合并它们的属性,并支持设置属性(使用名为TrySetMember的类似覆盖来允许您在缓存字典中动态设置值)。
当然,反射的开销可能不值得担心,但对于大型对象,这可能会限制它的影响。也许更有趣的是它给了你额外的灵活性。
https://stackoverflow.com/questions/2594527
复制相似问题