你是如何制作通用通用工厂的?

时间:2010-08-02 17:01:09

标签: c# .net generics dependency-injection ninject

我正在开发一个webmethod集合的客户端(Silverlight)接口。我试图避免为每个web方法编写任何自定义代码。所以我创建了一个ServiceCall<TResult>来处理每个调用,TResult指定服务的返回类型(我使用XmlSerializer来创建返回的实例)。客户端类公开了与每个web方法匹配的函数,该函数所要做的就是创建ServiceCall<TResult>的新实例,并将TResult指定为方法的预期返回类型。 这很好用。

我也在使用Ninject(依赖注入器)来尝试保持一切独立。 Ninject支持开放式泛型,这对我的ServiceCall<TResult>非常有用。

但这也意味着我正在注入对Ninject容器的引用。这隐藏了对绑定到容器的ServiceCall<TResult>的依赖。所以我想注入一个工厂来创建我的ServiceCall<TResult>实例。这并不棘手,但我想把它变成一个通用的通用工厂。这意味着我希望有Factory<T<>>这样的方法public T<TU> Createinstance<TU>()

但是我不知道如何创建一个类型参数的泛型类,它本身就是一个开放的genric。

.Net中的事件是否可行? - 或者我是否必须创建特定的ServiceCallFactory?

修改 我正在使用依赖关系的接口,但是没有必要将它们混合到这里的问题中,所以我编辑了这个问题。

回应Timwi: 使用依赖注入(DI)的常用方法是将接口绑定到您的实现,只有容器知道这些绑定。然后,您将对代码进行编码。这带来了许多优点。比我在这里提到的更多。
无论如何,它还排除了静态类(因为那将是对特定类的依赖)。相反,我将指示容器(在这种情况下为Ninject)始终为工厂界面提供相同的实例,例如行为。 这排除了public static class Factory<T>选项,因为它是静态的,如果它不是静态的,我现在需要使用每种类型的T,这有点挫败了使用泛型类的目的。
建议使用具有“完全通用”方法的非泛型类(如我在ServiceCall<MyResult>而不是MyResult中传递),这或多或少是我现在所做的(减去静态类部分)。 Ninject容器有一个Get方法,就像你的第二个建议一样 这个问题有两部分;首先它使我的代码直接依赖于一个容器(Ninject),但这对我来说并不是那么大的问题。令我恼火的是,如果你从外面看我的客户,你只会看到对Ninject的依赖。你不会知道,直到你运行尝试打电话,客户需要在Ninject注册的ServiceCall的实现工作。
但是如果Client contructor采用了Factory&gt;类型的参数,那么它会更加清晰。

无论如何,我认为这将是一个常见的问题,所以要么有一个共同的解决方案,要么它不是一个常见的问题,我试图做一些愚蠢的事情;) 我仍然没有进入依赖注入,所以很可能就是这种情况。

2 个答案:

答案 0 :(得分:4)

这是你在找什么:Generic Factory Pattern

namespace GenericFactoryPatternTestApp
{
    public class Factory< T >
    {
        private readonly Dictionary< string, Type > _factoryDictionary = new Dictionary< string, Type >();

        public Factory()
        {    
            Type[] types = Assembly.GetAssembly(typeof (T)).GetTypes();

            foreach (Type type in types)
            {
                if (!typeof (T).IsAssignableFrom(type) || type == typeof (T))
                {
                    // Incorrect type
                    continue;
                }

                // Add the type
                _factoryDictionary.Add(type.Name, type);
            }
        }

        public T Create< V >(params object[] args)
        {
            return (T) Activator.CreateInstance(_factoryDictionary[typeof (V).Name], args);
        }
    }
}

答案 1 :(得分:1)

所以,如果我理解你的话,你会有一个看起来像这样的课程:

public static class Factory<T<>>
{
    public static T<TU> CreateInstance<TU>() { /* ... */ }
}

然后你会怎么称呼它?喜欢这个?

var myServiceCall = Factory<ServiceCall<>>.CreateInstance<MyResult>();

是什么阻止你简单地宣布像这样的工厂......

public static class Factory<T>
{
    public static T CreateInstance() { /* ... */ }
}

......或者......

public static class Factory
{
    public static T CreateInstance<T>() { /* ... */ }
}

...然后像这样生成你的实例?

var myServiceCall = Factory<ServiceCall<MyResult>>.CreateInstance();
var myServiceCall = Factory.CreateInstance<ServiceCall<MyResult>>();

我很抱歉,如果我愚蠢,但我可能需要知道Ninject如何工作以及它如何让你进入工厂。