如何在C#中存储不同通用事物的列表

时间:2017-02-16 16:12:07

标签: c# generics collections

比如说我有这个基类

class Mangler<TInput, TOutput>
{
}

然后我制作了几个派生类

class StringToBytesMangler : Mangler<string, byte[]>
{
}

class IntToGuidMangler : Mangler<int, Guid>
{
}

如何存储Mangler<TInput, TOutput>的集合TInputTOutput在任何给定时间可能不同?

List<Mangler<?, ?>> list = new List<Mangler<?, ?>>();

list.Add(new StringToBytesMangler());
list.Add(new IntToGuidMangler());

这可能吗?

3 个答案:

答案 0 :(得分:2)

您需要一个非通用的Mangler基类。

List<Mangler> list = new List<Mangler>();

list.Add(new StringToBytesMangler());
list.Add(new IntToGuidMangler());

当然,这意味着您还需要拥有依赖TInputTOutput的方法的非通用版本。

答案 1 :(得分:2)

如果我正确理解了这个问题,那就不可能按照你的方式进行。 StringToBytesManglerIntToGuidMangler类型来自同一类型。您可以引入共享基类型,但我建议重新考虑设计 - 即使它们可以存储在同一个集合中,它们在语法上也没有任何共同之处(至少它没有在问题中显示)。

答案 2 :(得分:0)

泛型背后的整个想法是拥有通用代码,因此该类的类型可以被视为相同。根据您发布的内容,您很难看到您拥有的通用代码。

下面我有一个包含通用代码的类:

class Mangler<TInput, TOutput> 
   where TInput: ITInput 
   where TOutput: ITOutput {

   public TInput Input { get; set; }
   public TOutput Output { get; set; }
   public bool IsInputAGuid() {
      if (Guid.Parse(this.Input.SomeThing) == this.Output.SomeGuid ) {
         return true;
      }

      return false;
   }
}

您可以在上面的类中看到,当它从Guid将字符串解析为this.Input.Something,然后使用==对其执行this.Ouput.SomeGuid时,编译器是很高兴,因为我们已经制定了TInput必须实现接口ITInput的约束,因此编译器知道此行将起作用,而InputSomething作为string属性:

Guid.Parse(this.Input.SomeThing)

只要Something可用,编译器就不关心具体类型是什么。 TOuput的想法是一样的,但编译器希望它实现ITOutput,因此它需要Guid中的SomeGuid。这就是为什么编译器很乐意将字符串解析为guid,然后使用另一个也是==的东西对其执行Guid运算符。

以下是接口和一些实现它们的类:

internal interface ITInput {
   string SomeThing { get; set; }
}

internal interface ITOutput {
   Guid SomeGuid { get; set; }
}

internal class AnotherInput : ITInput {
   public string SomeThing { get; set; }
}

internal class SomeInput : ITInput {
   public string SomeThing { get; set; }
}

internal class SomeOutput : ITOutput {
   public Guid SomeGuid { get; set; }
}

internal class SomeOtherOutput : ITOutput {
   public Guid SomeGuid { get; set; }
}

最后,这里是我们可以一般地处理这些问题的用法:

var manglers = new List<Mangler<ITInput, ITOutput>>();

manglers.Add( new Mangler<ITInput, ITOutput>
{ Input = new SomeInput(), Output = new SomeOutput()  } );

manglers.Add( new Mangler<ITInput, ITOutput>
{ Input = new AnotherInput(), Output = new SomeOutput() } );

foreach( var thisMangler in manglers ) {
   var input = thisMangler.Input;
   var output = thisMangler.Output;
   var success = thisMangler.IsInputAGuid();
}

您可以在foreach中看到,无论具体类型如何,我们都可以在所有类型上调用InputOutputIsInputAGuid()

因此,在您的代码中找到哪些代码是通用的,然后将上述技术应用于它。您可以使用接口或基类来约束。