泛型多次派发 [英] Multiple Dispatch with Generics

查看:92
本文介绍了泛型多次派发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过提供使用泛型的工厂/构建器来抽象我的接口实现.但是,我在运行时遇到了多个调度和C#泛型的问题,这似乎有些奇怪.

I'm trying to abstract away my interface implementations by providing a factory/builder using generics. However, I'm running into an issue with multiple dispatch and C# generics at run time that's doing something that seems odd.

基本方案是我定义了几个接口:

The basic scenario is I've defined several interfaces:

public interface IAddressModel
{
}

public interface IUserModel
{
}

然后我有一个工厂类来返回实际的实现:

Then I have a factory class to return the actual implementations:

public class Factory
{
    public T BuildModel<T>()
    {
        return BuildModel(default(T));
    }

    public object BuildModel(object obj)
    {
        //this is here because the compiler will complain about casting T to
        //the first inteface parameter in the first defined BuildModel method
        return null;
    }

    public IAddressModel BuildModel(IAddressModel iModel)
    {
        //where AddressModel inherits from IAddressModel
        return new AddressModel();
    }

    public IUserModel BuildModel(IUserModel iModel)
    {
        //where UserModel inherits from IUserModel
        return new UserModel(); 
    }
}

问题在于工厂的调用方式如下:new Factory().BuildModel<IAddressModel>() 在运行时从泛型分派的BuildModel(...)方法始终是T的最小派生形式,在这种情况下始终是对象.

The issue is when the factory is called like this: new Factory().BuildModel<IAddressModel>() The BuildModel(...) method that is dispatched at run time from generics is always the least derived form of T, in this case always object.

但是,如果调用new Factory().BuildModel(default(IAddressModel));,则会分配正确的方法(最有可能是因为这是在编译时完成的).似乎使用泛型进行的动态分派不会检查大多数派生类型的方法,即使所调用的方法是在编译时还是在运行时都应相同.理想情况下,我想将BuildModel(...)方法设为私有,而只公开通用方法.还有另一种方法可以使动态调度在运行时调用正确的方法吗?我尝试将BuildModel<>()实现更改为return BuildModel((dynamic)default(T)),但这会引发运行时错误,导致无法确定要分派的方法.也许有办法做到这一点,并且要有更多的接口?

However, if you call new Factory().BuildModel(default(IAddressModel)); the correct method is displatched (most likely because this is done at compile time). It seems that dynamic dispatch with generics doesn't check the methods for the most derived type even though the method called should be the same whether it's done at compile time or run time. Ideally I'd like to make the BuildModel(...) methods private and only expose the generic method. Is there another way to get dynamic displatch to call the correct method at run time? I've tried changing the BuildModel<>() implementation to return BuildModel((dynamic)default(T)) but this throws a run time error about not being able to determine which method to dispatch. Is there maybe a way to do this with contravariance and more interfaces?

推荐答案

您也许可以根据参数类型T自己进行调度:

You might be able do the dispatch yourself based on the argument type T:

public class Factory
{
    private Dictionary<Type, Func<object>> builders = new Dictionary<Type, Func<object>>
    {
        { typeof(IAddressModel), BuildAddressModel },
        { typeof(IUserModel), BuildUserModel }
    };

    public T Build<T>()
    {
        Func<object> buildFunc;
        if (builders.TryGetValue(typeof(T), out buildFunc))
        {
            return (T)buildFunc();
        }
        else throw new ArgumentException("No builder for type " + typeof(T).Name);
    }

    private static IAddressModel BuildAddressModel()
    {
        return new AddressModel();
    }

    private static IUserModel BuildUserModel()
    {
        return new UserModel();
    }
}

这篇关于泛型多次派发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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