Wątpię, możesz tylko uzyskać lub ustawić "właściwości" (lub events) z ExpandoObject
, a nie definiować nowych metod. Jeśli chcesz to zrobić, musisz utworzyć własny obiekt dynamiczny, do którego dodasz swoich członków.
Ale czuję, że muszę to powiedzieć, dlaczego zamiast tego użyć kompozycji? Utwórz klasę, do której dodajesz swoje metody i posiadasz właściwość dla expando.
class MyClass
{
public dynamic Expando { get; } = new ExpandoObject();
public void MyMethod<T>() { }
}
Jeśli koniecznie chciał to zrobić, można utworzyć dynamiczny obiekt z dynamicznym meta obiektu owijki nad ExpandoObject
. Następnie w opakowaniu przesuń wszystkie wiązania do swoich członków do dynamicznego obiektu, a wszystkie pozostałe do rozszerzenia. Obiekt będzie tym, co go zdefiniujesz, z funkcjonalnością expando.
np
// 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();
}
}
Dzięki temu można go używać tak jak w przypadku każdego obiektu 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
Będziesz po prostu potrzebują 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();
}
Czy byłbyś w porządku, tworząc klasę, która ma na niej metodę 'Query'? –
usr
Podejrzewam, że nie jest to możliwe, ponieważ szablony są kompilowane do unikalnych klas i wywołań. Może to być możliwe dzięki emitowaniu kodu IL. – Rob
http: // stackoverflow.com/questions/3712732/how-to-create-a-generic-list-with-a-dynamic-object-type? rq = 1 ... hmm ... może się to okazać względne –