Ne dubito, è possibile solo ottenere o impostare "proprietà" (o events) di un ExpandoObject
, non definire nuovi metodi. Se si desidera farlo, sarà necessario creare il proprio oggetto dinamico per il quale si aggiungono i propri membri.
Ma mi sento di doverlo dire, perché non usare la composizione invece? Crea una classe a cui aggiungi i tuoi metodi e disponi di una proprietà per l'expando.
class MyClass
{
public dynamic Expando { get; } = new ExpandoObject();
public void MyMethod<T>() { }
}
Se è assolutamente voluto fare questo, è possibile creare un oggetto dinamico con una dinamica involucro oggetto meta su una ExpandoObject
. Quindi nel wrapper, inoltra tutti i binding ai tuoi membri al tuo oggetto dinamico e tutti gli altri al expando. L'oggetto sarebbe quello che tu definisci, con la funzionalità di un expando.
esempio,
// be sure to explicitly implement IDictionary<string, object>
// if needed forwarding all calls to the expando
class ExtendedExpandoObject : IDynamicMetaObjectProvider
{
DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) => new MyMetaObject(parameter, this);
public ExtendedExpandoObject(ExpandoObject expandoObject = null)
{
Value = expandoObject ?? new ExpandoObject();
}
public ExpandoObject Value { get; }
// the new methods
public string GetMessage() => "GOT IT!";
public string GetTypeName<T>() => typeof(T).Name;
// be sure to implement methods to combine results (e.g., GetDynamicMemberNames())
class MyMetaObject : DynamicMetaObjectWrapper
{
public MyMetaObject(Expression parameter, ExtendedExpandoObject value)
: base(new DynamicMetaObject(parameter, BindingRestrictions.Empty, value))
{
var valueParameter = Expression.Property(
Expression.Convert(parameter, typeof(ExtendedExpandoObject)),
"Value"
);
IDynamicMetaObjectProvider provider = value.Value;
ValueMetaObject = provider.GetMetaObject(valueParameter);
}
protected DynamicMetaObject ValueMetaObject { get; }
public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
{
if (IsMember(binder.Name))
return base.BindGetMember(binder);
return ValueMetaObject.BindGetMember(binder);
}
public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
{
if (IsMember(binder.Name))
return base.BindSetMember(binder, value);
return ValueMetaObject.BindSetMember(binder, value);
}
private bool IsMember(string name) => typeof(ExtendedExpandoObject).GetMember(name).Any();
}
}
Con questo, si potrebbe usare come si farebbe con qualsiasi oggetto expando.
dynamic expando = new ExtendedExpandoObject();
Console.WriteLine(expando.Value); // the original expando
expando.Length = 12; // set a new property on the expando
Console.WriteLine(expando.Length); // get a property on the expando
Console.WriteLine(expando.GetMessage()); // call the new method
Console.WriteLine(expando.GetTypeName<ExtendedExpandoObject>()); // call the generic method
Console.WriteLine(expando.Value.Length); // get the property on the original expando
ti basta la DynamicMetaObjectWrapper:
public abstract class DynamicMetaObjectWrapper : DynamicMetaObject
{
protected DynamicMetaObjectWrapper(DynamicMetaObject metaObject)
: base(metaObject.Expression, metaObject.Restrictions, metaObject.Value)
{
BaseMetaObject = metaObject;
}
public DynamicMetaObject BaseMetaObject { get; }
public override DynamicMetaObject BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg) => BaseMetaObject.BindBinaryOperation(binder, arg);
public override DynamicMetaObject BindConvert(ConvertBinder binder) => BaseMetaObject.BindConvert(binder);
public override DynamicMetaObject BindCreateInstance(CreateInstanceBinder binder, DynamicMetaObject[] args) => BaseMetaObject.BindCreateInstance(binder, args);
public override DynamicMetaObject BindDeleteIndex(DeleteIndexBinder binder, DynamicMetaObject[] indexes) => BaseMetaObject.BindDeleteIndex(binder, indexes);
public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder) => BaseMetaObject.BindDeleteMember(binder);
public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes) => BaseMetaObject.BindGetIndex(binder, indexes);
public override DynamicMetaObject BindGetMember(GetMemberBinder binder) => BaseMetaObject.BindGetMember(binder);
public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args) => BaseMetaObject.BindInvoke(binder, args);
public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) => BaseMetaObject.BindInvokeMember(binder, args);
public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value) => BaseMetaObject.BindSetIndex(binder, indexes, value);
public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) => BaseMetaObject.BindSetMember(binder, value);
public override DynamicMetaObject BindUnaryOperation(UnaryOperationBinder binder) => BaseMetaObject.BindUnaryOperation(binder);
public override IEnumerable<string> GetDynamicMemberNames() => BaseMetaObject.GetDynamicMemberNames();
}
Ti andrebbe bene creare una classe con un metodo 'Query'? –
usr
Sospetto che ciò non sia possibile, poiché i modelli vengono compilati in classi e chiamate univoche. Potrebbe essere possibile emettendo il codice IL, comunque. – Rob
http: // stackoverflow.it/questions/3712732/how-to-create-a-generic-list-con-a-dynamic-object-type? rq = 1 ... hmm ... questo potrebbe dimostrarsi relativo –