2017-02-16 15 views
2

Скажем, например, у меня есть этот базовый классКак хранить список различных родовых вещей в C#

class Mangler<TInput, TOutput> 
{ 
} 

А потом я делаю пару производных классов

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

class IntToGuidMangler : Mangler<int, Guid> 
{ 
} 

Как хранить сбор Mangler<TInput, TOutput>, где TInput и TOutput могут отличаться в любой момент времени?

т.е.

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

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

Возможно ли это?

+1

'Mangler ' и 'Mangler ' - это совершенно разные типы, поэтому единственным общим списком для их хранения может быть «Список ». Возможно, вы можете получить «Mangler » из другого базового класса или интерфейса и использовать этот тип для списка. –

+1

Проверьте [Ковариация и контравариантность] (https://blogs.msdn.microsoft.com/csharpfaq/2010/02/16/covariance-and-contravariance-faq/). –

+0

@AlexB. Хороший комментарий, хотя 'string' и' int' и 'byte []' и 'Guid' - несколько несвязанные типы. – Codor

ответ

2

Если я правильно понял вопрос, это невозможно, как вы его пробовали. Типы StringToBytesMangler и IntToGuidMangler do не происходят из того же типа. Вы можете ввести общий базовый тип, но я рекомендую пересмотреть дизайн - даже если они могут быть сохранены в одной коллекции, они синтаксически не будут иметь ничего общего (по крайней мере, это не показано в вопросе).

2

Вам нужен необорудованный базовый класс Mangler.

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

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

Конечно, это означает, что вы также должны иметь не непатентованные методы, которые зависят от TInput или TOutput.

+0

Или «объект». – Sinatr

+0

@Sinatr, да, но это уродливо, и это не позволяет вам определять методы, которые раскрывают функциональность класса. –

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 так что компилятор знает, эта линия будет работать и Input будет Something как string собственности:

Guid.Parse(this.Input.SomeThing) 

Компилятору все равно, какой тип бетона до тех пор, пока Something не доступен. Это та же идея для TOuput, но компилятор ожидает, что он реализует ITOutput, поэтому он ожидает Guid в SomeGuid. Вот почему компилятор с удовольствием разбирает строку в руководстве, а затем выполняет оператор == на ней с другой вещью, которая также является 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 независимо от конкретный тип, мы можем назвать Input, Output и IsInputAGuid() на всех из них.

Итак, в коде найдите, какой код является общим, а затем примените к нему вышеуказанную технику. Вы можете использовать интерфейсы или базовый класс для своих ограничений.

+0

Итак, вся идея заключается в использовании интерфейса. Правильно ли я это понимаю? – Bigeyes

+0

Интерфейс или базовый класс, который имеет общий код, поэтому вы можете обрабатывать объекты одинаково, потому что они имеют общий интерфейс. – CodingYoshi