Подтвердить что ты не робот

С# Общие и полиморфизм: оксюморон?

Я просто хочу подтвердить, что я понял о Generics в С#. Это появилось в нескольких базовых кодах, с которыми я работал, когда общий базовый класс используется для создания производных экземпляров типа безопасных. Очень простой пример того, что я говорю,

public class SomeClass<T>
{
    public virtual void SomeMethod(){ }
}

public class DeriveFrom :SomeClass<string>
{
    public override void SomeMethod()
    {
        base.SomeMethod();
    }
}

Проблема возникает, когда я хочу использовать производные экземпляры полиморфным способом.

public class ClientCode
{
    public void DoSomethingClienty()
    {
        Factory factory = new Factory();
        //Doesn't compile because SomeClass needs a type parameter!
        SomeClass someInstance = factory.Create();

        someInstance.SomeMethod();
    }
}

Кажется, что когда вы вводите Generic в иерархию наследования или интерфейс, вы больше не сможете использовать это семейство классов полиморфным способом, за исключением, возможно, внутреннего для себя. Это правда?

4b9b3361

Ответ 1

Насколько я могу судить, для употребления кода не нужны особенности общего класса (т.е. он не зависит от того, что T). Итак, почему бы вам не ввести интерфейс, который будет реализован SomeClass<T>, и использовать экземпляр этого интерфейса.

например:.

public interface ISome
{
    void SomeMethod();
}

public class SomeClass<T>: ISome
{
    public virtual void SomeMethod(){ }
}

public void DoSomethingClienty()
{
    Factory factory = new Factory();
    ISome someInstance = factory.Create();

    someInstance.SomeMethod();
}

Теперь подклассы SomeClass<T> могут работать по-разному на разных T s, но код потребления не изменится.

Ответ 2

Я думаю, вы неправильно понимаете суть дженериков. Generics позволяет вам обобщать класс, требующий типа, но не особенно заботится о том, какой тип. Например, List<string> - это список строк, но что бы было List? Это довольно бесполезная концепция, чтобы иметь список ничего.

Каждый специализированный класс (т.е. List<string>) имеет свой собственный тип, и компилятор рассматривает его как таковой. Можно получить сам общий тип (typeof(List<>)), но в большинстве случаев он бесполезен, и вы, конечно же, не можете сделать его экземпляр.

Ответ 3

Я бы предпочел использовать абстрактный класс, чтобы действовать как основа всех родовых типов.

public abstract class SomeClass 
{
    public abstract void SomeMethod();
}

public class SomeClass<T> : SomeClass
{
    public override void SomeMethod() { }            
}

public class DeriveFrom<String> : SomeClass<String>
{
    public override void SomeMethod() { base.SomeMethod(); }            
}

Ответ 4

Я думаю, что вы ищете:

  SomeClass(of someType) someInstance = factory(of someType).Create();
or maybe
  SomeClass(of someType) someInstance = factory.Create(of someType)();
or
  SomeClass(of someType) someInstance = factory.Create();

Можно создать набор классов factory для создания разных общих классов или иметь factory с параметром generic type, чтобы указать, какой родовой тип он должен создать (обратите внимание, что в любом случае параметр типа является параметром типа для универсального класса, а не является самим общим классом). Также возможно иметь factory, который предназначен для возврата экземпляров одной конкретной формы родового типа.

Ответ 5

Кажется, что как только вы вводите Generic в иерархию или интерфейс наследования, вы больше не сможете использовать это семейство классов полиморфным способом.

Правильно, это очень похоже на эту ситуацию:

class StringContainer
{
}

class IntContainer
{
}

StringContainer container = new IntContainer(); // fails to compile

но вы можете сделать это:

class Container
{
}

class Container<T> : Container
{
}

Container container = new Container<String>(); // OK

Ответ 6

public Class ReflectionReport<T> 
{
    // This class uses Reflection to produce column-based grids for reporting.  
    // However, you need a type in order to know what the columns are. 
}

... so, in another class you have...

public Class ReflectionReportProject {
    ReflectionReport<Thang> thangReport = new ReflectionReport<Thang>(); 
    ReflectionReport<Thong> thongReport = new ReflectionReport<Thong>(); 



    ... some more stuff ...

    // Now, you want to pass off all of the reports to be processed at one time....
    public ReflectionReport<????>[] ProvideReports() 
    {
        return new ReflectionReport<????>[] { thangReport, thongReport } ;
    }
}