是否可以在动态/ ExpandoObject上创建泛型方法 [英] Is it possible to create a Generic Method on an dynamic / ExpandoObject

查看:79
本文介绍了是否可以在动态/ ExpandoObject上创建泛型方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我怀疑这是不可能的,但是我没有看到明确的编号。

I suspect this isn't possible, but I haven't seen a definitive no.

我当前的(有效的)实现方法如下。

My current (working) implementation is as followed..

public static Main(param args[])
{
    dynamic Repository = GetRepository();

    var query = (Repository.QueryUser() as IQueryable<User>)
                .Where(user => user.Name.ToLower().Contains("jack"));
}

public static dynamic GetRepository()
{
    dynamic repo = new System.Dynamic.ExpandoObject();        
    repo.QueryUser = new [] { new User() { Name = "Jack Sparrow"}}.AsQueryable<User>();
    return repo;
}

为了更好地模拟Generic方法的(常用)存储库接口,我会喜欢实现以下内容:

To better mock the (commonly used) Repository interface with Generic methods, I would like to implement something like the following:

public interface IRepository
{
    IQueryable<T> Query<T>();
}

public static Main(param args[])
{
    IRepository Repository = GetRepository();  // return a dynamic

    var query = Repository.Query<User>() 
                 .Where(user => user.Name.ToLower().Contains("jack"));
}


public static dynamic GetRepository()
{
    dynamic repo = new System.Dynamic.ExpandoObject();

    // the issue is on the following line
    repo.Query<User> = new [] {
                          new User() {
                              Name = "Jack Sparrow"
                          }
                      }.AsQueryable<User>();
    return repo;
}

是否有可能的解决方法(在System.Dynamic命名空间中使用

Is there a possible workaround for this (using something in the System.Dynamic namespace perhaps)?

推荐答案

我对此表示怀疑,您只能获取或设置属性(或 ExpandoObject 的事件),而不是定义新方法。//stackoverflow.com/a/1663044/390278>如果要这样做,则必须创建自己的动态对象,并为其添加自己的成员。

I doubt it, you can only get or set "properties" (or events) of an ExpandoObject, not define new methods. If you wanted to do so, you'll have to create your own dynamic object for which you add your own members.

但是我觉得我必须这样说,为什么不只是使用合成吗?创建一个添加了方法的类,并为expando提供一个属性。

But I feel I have to say this, why not just use composition instead? Create a class to which you add your methods, and have a property for the expando.

class MyClass
{
    public dynamic Expando { get; } = new ExpandoObject();
    public void MyMethod<T>() { }
}






如果您绝对想这样做,可以在 ExpandoObject 上创建一个带有动态元对象包装的动态对象。然后在包装器中,将所有绑定转发给您的成员到动态对象,并将所有其他绑定转发给expando。该对象将是您定义的对象,具有expando的功能。


If you absolutely wanted to do this, you could create a dynamic object with a dynamic meta object wrapper over an ExpandoObject. Then in the wrapper, forward all bindings to your members to your dynamic object, and all others to the expando. The object would be what you define it, with the functionality of an expando.

例如,

// 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();
    }
}

有了它,您可以像使用它一样使用它

With this, you could use it like you would with any expando object.

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

中获取属性,您只需要DynamicMetaObjectWrapper:

You'll just need the 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();
}

这篇关于是否可以在动态/ ExpandoObject上创建泛型方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆