如何创建一个通用的泛型工厂?

4
我正在为一组Web方法创建一个客户端(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>()方法。
但我不知道如何创建一个类型参数本身是开放式泛型的通用类。
在.NET中是否可能? - 还是我必须创建特定的ServiceCallFactory?
注:我正在使用依赖项的接口,但没有必要将它们混入问题中,因此我从问题中编辑了它们。
作为对Timwi的回应: 使用依赖注入(DI)的常见方法是将接口绑定到实现,只有容器知道这些绑定。然后您编写针对接口的代码。这带来了很多优势。我不能在这里一一列举。
无论如何,它也排除了静态类(因为那将是对特定类的依赖)。相反,我会指示容器(在这种情况下是Ninject)始终向我提供与工厂接口相同的实例,以单例方式。
这就排除了public static class Factory<T>选项,因为它是静态的,如果它不是静态的,我需要知道我将要使用的每种类型的T,这在某种程度上破坏了拥有通用类的目的。
有一个非通用类,并且具有“完全通用”的方法(例如,我传递ServiceCall<MyResult>而不仅仅是MyResult),是我正在做的事情(不包括静态类部分)。 Ninject容器有一个Get方法,就像你第二个建议一样。
问题在于有两个部分;首先,它使我的代码直接依赖于一个容器(Ninject),但这对我来说并不是真正的大问题。令我困扰的是,如果从外部查看我的客户端,您只会看到对Ninject的依赖性。您只有在尝试进行调用时才会知道客户端需要在Ninject中注册ServiceCall的实现才能正常工作。
但是,如果Client构造函数接受Factory>类型的参数,则会更清晰明了。

无论如何,我认为这应该是一个常见的问题,因此要么有一个常见的解决方案,要么它不是一个常见的问题,而我正在尝试做一些愚蠢的事情 ;)
我还不太了解依赖注入,所以很可能是这种情况。


“IServiceCall”是一个特定服务调用的示例(例如“foo”),还是您正在构建的API的实际接口? - Kirk Woll
这是一个接口。我具体的实现是ServiceCall。我使用它来依赖于接口而不是特定的实现。 但它可能与这个问题无关。我会编辑帖子。 - Jacob Poul Richardt
2个回答

4

这是您要查找的内容吗:通用工厂模式

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

2

所以如果我没理解错的话,你会有一个类看起来有点像这样:

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是如何工作的,以及它如何允许您传递一个工厂。


由于此处空间有限,我将在问题中留下评论。 - Jacob Poul Richardt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接