【问题标题】:Dictionary of classes that implement a generic interface实现通用接口的类字典
【发布时间】:2013-10-10 11:53:20
【问题描述】:

我有一个泛型接口,其中包含两个具有严格泛型约束的类型参数,以及针对不同组合的多个实现。

public interface IResolver<TIn, TOut> where ... {...}

我想创建一个(静态)解析器工厂,它将存储已知实现的实例,并按照以下方式为它们提供服务:

public static ResolverFactory{

   public static IResover<TIn, TOut>  GetResolver<TIn, TOut> where ... ()
   {
       //access some storage dictionary to return the correctly typed instance
   }
}

如何创建这样一个容器,它可以同时存储IResover&lt;Entity1, Entity2&gt;IResolver&lt;Entity3, Entity4&gt;

我能想到的一个选择是使用单独的非通用“标记”接口,例如:

public interface IResolver {} 
public interface IResolver<TIn, TOut> : IResolver where .... 
{...}

并使用

Dictionary<Type, Dictionary <Type, IResolver>> storage;

public RegisterResolver(IResolver resolver)
{
   //add to storage - how?
}

但这种情况基本上会使泛型参数上的约束无效。 此外,当添加IResolver 时,获得IResolver&lt;TIn, TOut&gt; 的泛型类型或多或少是不可能的。

有没有更好的解决方案?

【问题讨论】:

  • 我不会说它会使约束无效。它仍然是IResolver&lt;TIn, TOut&gt;实例
  • 我不确定我是否理解您的无效约束问题。这些约束仅在您的 ResolverFactory 之外很重要,并且由您的 GetResolve&lt;TIn, TOut&gt; 方法的签名强制执行。在 ResolverFactory 内部,存储对象的方式并不重要。
  • @KooKiz: 是的,GetResolver 方法也有同样的限制,因此不可能得到无效结果,但仍然可以注册一个 IResolver 实现,即不是IResolver&lt;TIn, TOut&gt;
  • 也许我错过了什么,常见的 IResolver 接口看起来不错,但你为什么不让 RegisterResolver 通用呢? public RegisterResolver(IResolver 解析器)

标签: c# generics factory


【解决方案1】:

您的问题中我可能遗漏了一些明显的东西,因为我不明白问题出在哪里。

首先,我声明一个带有约束的IResolver&lt;TIn, TOut&gt; 接口:

public interface IResolver<TIn, TOut>
    where TIn : Stream 
{

}

然后,我创建一个ResolverFactory,其中的约束由RegisterResolverGetResolver 方法强制执行。对象的实际存储方式并不重要,因为存储不会暴露在类之外。封装保持一致性:

public static class ResolverFactory
{
    private static Dictionary<Type, object> storage = new Dictionary<Type, object>();

    public static void RegisterResolver<TIn, TOut>(IResolver<TIn, TOut> resolver) where TIn : Stream 
    {
        storage[typeof(IResolver<TIn, TOut>)] = resolver;
    }

    public static IResolver<TIn, TOut> GetResolver<TIn, TOut>() where TIn : Stream
    {
        return storage[typeof(IResolver<TIn, TOut>)] as IResolver<TIn, TOut>;
    }
}

【讨论】:

  • +1 是的,我猜,使Register 泛型可以解决问题。在这种情况下,我可以将非通用接口设置为内部接口,并限制它在我的程序集中的使用。
【解决方案2】:

喜欢 KooKiz 的答案,但没有强制转换,也没有字典。用法类似。

//Rather than:
var res = ResolverFactory.GetResolver<Stream, Hat>();
//You Do:
var res = ResolverFactory<Stream, Hat>.GetResolver();

只是移动了泛型参数,增加了在更少位置定义泛型约束的优势。

public interface IResolver<TIn, TOut>
    where TIn : Stream
{
}

//Still static, but now there is one per TIn,TOut pair
//so no need for dictionary, so also no need for casting.
public static class ResolverFactory<TIn, TOut> where TIn : Stream
{
    private static IResolver<TIn, TOut> _resolver;

    public static void RegisterResolver(IResolver<TIn, TOut> resolver)
    {
        _resolver = resolver;
    }

    public static IResolver<TIn, TOut> GetResolver()
    {
        return _resolver;
    }
}


internal class Program
{
    private static void Main(string[] args)
    {
        ResolverFactory<Stream, Hat>.RegisterResolver(new MyStreamToHatResolver());

        var res = ResolverFactory<Stream, Hat>.GetResolver();
    }
}

【讨论】:

  • 这将为每对参数创建一个单独的静态类,并且由于我需要使用一些“默认”功能对其进行扩展,因此它不起作用。 +1,这是个好主意。
  • 确实如此。并且以这种方式处理多线程场景更容易。另一方面,您将失去列出/删除所有解析器的能力,因此正确的解决方案取决于需求(像往常一样)。
  • 听起来你对这个单身人士有很大的计划!我会有点担心。将其作为解析器。每班1个工作。但是,如果您确实添加了更多功能,除非它们也共享静态状态,否则它仍然可以工作?在这种情况下,我会更加担心。
  • @weston:不,这只是一些后备逻辑,最好在那里完成。静态不会成为问题,因为解析器本身主要是纯函数。
  • @KooKiz 好点。可以通过将字典移动到单独的静态类来组合解决方案。
猜你喜欢
  • 1970-01-01
  • 2022-11-18
  • 1970-01-01
  • 1970-01-01
  • 2022-11-28
  • 2011-02-23
  • 2017-08-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多