问题描述
我有说我发送给外部库方法,需要一个对象的ExpandoObject。从我所看到的这个外部的lib使用TypeDescriptor.GetProperties内部这似乎会导致一些问题,我的ExpandoObject。
我可以去与一个匿名对象,而不是这似乎工作,但它更方便,我使用ExpandoObject。
我是否需要建立自己的DynamicObject和照顾它自己通过实现ICustomTypeDescriptor还是我失去了一些东西在这里。
想法?
更新
除了用下面somedave(按照注释)的答案,我说这班
公共类ExpandoObjectTypeDescriptionProvider:TypeDescriptionProvider
{
私人静态只读TypeDescriptionProvider m_Default = TypeDescriptor.GetProvider(typeof运算(ExpandoObject));
公共ExpandoObjectTypeDescriptionProvider()
:基地(m_Default)
{
}
公众覆盖ICustomTypeDescriptor GetTypeDescriptor(类型的objectType,对象实例)
{
VAR defaultDescriptor = base.GetTypeDescriptor(的objectType,实例);
返回实例==空? defaultDescriptor:
新ExpandoObjectTypeDescriptor(实例);
}
}
和注册这样的:
动态参数=新ExpandoObject();
TypeDescriptor.AddProvider(新ExpandoObjectTypeDescriptionProvider(),参数);
实现ICustomTypeDescriptor其实并不是那么难。下面是一些示例code,我从一些工作,我做了的WinForms属性网格(它使用TypeDescriptor和的PropertyDescriptor)改编。诀窍是,也能实现,你可以从 ICustomTypeDescriptor.GetProperties回传适当的PropertyDescriptor类()
。值得庆幸的ExpandoObject使得这个pretty的通过实施简单的的IDictionary<字符串,对象>
为它动态检索的关键字和值。请记住,这可能会或可能无法正常工作(我没有测试过它),它可能不会对ExpandoObjects有很多嵌套属性的工作。
公共类ExpandoTypeDescriptor:ICustomTypeDescriptor
{
私人只读ExpandoObject _expando;
公共ExpandoTypeDescriptor(ExpandoObject的expando)
{
_expando = Expando的;
}
//只需使用从TypeDescriptor的默认行为对于大多数的这些
//这可能需要一些调整,以正确的ExpandoObjects虽然工作...
公共字符串GetComponentName()
{
返回TypeDescriptor.GetComponentName(这一点,真正的);
}
公共EventDescriptor GetDefaultEvent()
{
返回TypeDescriptor.GetDefaultEvent(这一点,真正的);
}
公共字符串GetClassName()
{
返回TypeDescriptor.GetClassName(这一点,真正的);
}
公共EventDescriptorCollection GetEvents(属性[]属性)
{
返回TypeDescriptor.GetEvents(本,属性,真正的);
}
EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents()
{
返回TypeDescriptor.GetEvents(这一点,真正的);
}
公共的TypeConverter GetConverter()
{
返回TypeDescriptor.GetConverter(这一点,真正的);
}
公共对象GetPropertyOwner(PropertyDescriptor与PD)
{
返回_expando;
}
公共AttributeCollection在GetAttributes()
{
返回TypeDescriptor.GetAttributes(这一点,真正的);
}
公共对象GetEditor(类型editorBaseType)
{
返回TypeDescriptor.GetEditor(这一点,editorBaseType,真正的);
}
公众的PropertyDescriptor GetDefaultProperty()
{
返回null;
}
//这是其中的GetProperties()调用是
//忽略的属性就目前而言,如果它需要的支持,将不得不实施
//应该够简单的使用...
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
返程((ICustomTypeDescriptor)本).GetProperties(新属性[0]);
}
公共PropertyDescriptorCollection的GetProperties,(属性[]属性)
{
//这只是蒙上了ExpandoObject到一个IDictionary<字符串,对象>获取密钥
返回新PropertyDescriptorCollection(
((IDictionary的<字符串,对象>)_ Expando的)。键
。选择(X =>新建ExpandoPropertyDescriptor(((IDictionary的<字符串,对象>的expando)_),X))
.ToArray());
}
//可以获取和设置属性嵌套的PropertyDescriptor类
// ExpandoObject在运行时动态
私有类ExpandoPropertyDescriptor:的PropertyDescriptor
{
私人只读IDictionary的<字符串,对象> _expando;
私人只读字符串_name;
公共ExpandoPropertyDescriptor(IDictionary的<字符串,对象>的expando,字符串名称)
:基地(名,空)
{
_expando = Expando的;
_name =名称;
}
公众覆盖类型属性类型
{
{返回_expando [_name] .GetType(); }
}
公众覆盖无效的SetValue(组件对象,对象的值)
{
_expando [_name] =值;
}
公众覆盖对象的GetValue(对象组件)
{
返回_expando [_name]
}
公众覆盖BOOL的IsReadOnly
{
得到
{
//你也许可以在这里实现一些更好的逻辑
返回false;
}
}
公众覆盖类型COMPONENTTYPE
{
获得{返回null; }
}
公众覆盖布尔CanResetValue(对象组件)
{
返回false;
}
公众覆盖无效ResetValue(对象组件)
{
}
公众覆盖布尔ShouldSerializeValue(对象组件)
{
返回false;
}
公众覆盖字符串类别
{
{返回的String.Empty; }
}
公众覆盖字符串。
{
{返回的String.Empty; }
}
}
}
I've got an ExpandoObject that I'm sending to an external library method which takes an object. From what I've seen this external lib uses TypeDescriptor.GetProperties internally and that seems to cause some problems with my ExpandoObject.
I could go with an anonymous object instead and that seems to work but it much more convenient for me to use the ExpandoObject.
Do I need to construct my own DynamicObject and take care of it myself by implementing ICustomTypeDescriptor or am I missing something here.
Ideas?
Update
Besides the answer by somedave below (as per the comments), I added this class
public class ExpandoObjectTypeDescriptionProvider : TypeDescriptionProvider
{
private static readonly TypeDescriptionProvider m_Default = TypeDescriptor.GetProvider(typeof(ExpandoObject));
public ExpandoObjectTypeDescriptionProvider()
:base(m_Default)
{
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
var defaultDescriptor = base.GetTypeDescriptor(objectType, instance);
return instance == null ? defaultDescriptor :
new ExpandoObjectTypeDescriptor(instance);
}
}
and registered it like this:
dynamic parameters = new ExpandoObject();
TypeDescriptor.AddProvider(new ExpandoObjectTypeDescriptionProvider(), parameters);
Implementing ICustomTypeDescriptor actually isn't all that hard. Here is some sample code I adapted from some work I did with WinForms property grids (which uses TypeDescriptor and PropertyDescriptor). The trick is to also implement an appropriate PropertyDescriptor class that you can pass back from ICustomTypeDescriptor.GetProperties()
. Thankfully the ExpandoObject makes this pretty simple by implementing IDictionary<string, object>
for dynamic retrieval of it's keys and values. Keep in mind that this may or may not work correctly (I haven't tested it) and it probably won't work for ExpandoObjects with lots of nested properties.
public class ExpandoTypeDescriptor : ICustomTypeDescriptor
{
private readonly ExpandoObject _expando;
public ExpandoTypeDescriptor(ExpandoObject expando)
{
_expando = expando;
}
// Just use the default behavior from TypeDescriptor for most of these
// This might need some tweaking to work correctly for ExpandoObjects though...
public string GetComponentName()
{
return TypeDescriptor.GetComponentName(this, true);
}
public EventDescriptor GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this, true);
}
public string GetClassName()
{
return TypeDescriptor.GetClassName(this, true);
}
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}
EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents()
{
return TypeDescriptor.GetEvents(this, true);
}
public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}
public object GetPropertyOwner(PropertyDescriptor pd)
{
return _expando;
}
public AttributeCollection GetAttributes()
{
return TypeDescriptor.GetAttributes(this, true);
}
public object GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}
public PropertyDescriptor GetDefaultProperty()
{
return null;
}
// This is where the GetProperties() calls are
// Ignore the Attribute for now, if it's needed support will have to be implemented
// Should be enough for simple usage...
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[0]);
}
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
// This just casts the ExpandoObject to an IDictionary<string, object> to get the keys
return new PropertyDescriptorCollection(
((IDictionary<string, object>)_expando).Keys
.Select(x => new ExpandoPropertyDescriptor(((IDictionary<string, object>)_expando), x))
.ToArray());
}
// A nested PropertyDescriptor class that can get and set properties of the
// ExpandoObject dynamically at run time
private class ExpandoPropertyDescriptor : PropertyDescriptor
{
private readonly IDictionary<string, object> _expando;
private readonly string _name;
public ExpandoPropertyDescriptor(IDictionary<string, object> expando, string name)
: base(name, null)
{
_expando = expando;
_name = name;
}
public override Type PropertyType
{
get { return _expando[_name].GetType(); }
}
public override void SetValue(object component, object value)
{
_expando[_name] = value;
}
public override object GetValue(object component)
{
return _expando[_name];
}
public override bool IsReadOnly
{
get
{
// You might be able to implement some better logic here
return false;
}
}
public override Type ComponentType
{
get { return null; }
}
public override bool CanResetValue(object component)
{
return false;
}
public override void ResetValue(object component)
{
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
public override string Category
{
get { return string.Empty; }
}
public override string Description
{
get { return string.Empty; }
}
}
}
这篇关于暴露的ExpandoObject的性质的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!