2015-11-19 3 views
1

У меня есть базовый класс с несколькими производными классами:Как преобразовать класс <Derived> в класс <Base>?

class Base { } 

class Derived1 : Base { } 

class Derived2 : Base { } 

Тогда у меня есть класс, работник, который принимает этот класс в качестве универсального типа:

class WorkerClass<T> where T : Base, new() 
{ 
    WorkerClass() { } 

    void DoStuff() 
    { 
     T container = new T(); 
     // do stuff 
    } 
} 

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

void DoStuff(Type type) 
{ 
    WorkerClass<Base> worker_class = null; 

    if(type == typeof(Derived1)) 
    { 
     worker_class = new WorkerClass<Derived1>(); // compiler error 
    } 
    else if(type == typeof(Derived2)) 
    { 
     worker_class = new WorkerClass<Derived2>(); // compiler error 
    } 

    // lots of common code with worker_class 
    worker_class.DoStuff(); 
} 

Но компилятор жалуется неявно литье WorkerClass<Derived> в WorkerClass<Base>. Явное кастинг также дает ошибку. Компилятор предлагает определить public static implicit operator WorkerClass<T>(WorkerClass<Derived>), но я не уверен, как будет выглядеть этот код. Я мог бы, очевидно, поставить всю логику внутри if-else, но это кажется ненужным повторением.

+1

вместо 'DoStuff (типа Type)' использовать универсальный метод. 'DoStuff () где T2: Base, new()' –

ответ

2

Я может быть неправильное ваше намерение, но я думаю, вы могли бы сделать что-то вроде этого, используя воспроизведенных с ограничениями:

void DoStuff<T>() where T : Base, new() 
{ 
    WorkerClass<T> worker_class = new WorkerClass<T>(); 

    // lots of common code with worker_class 
    worker_class.DoStuff(); 
} 

Оттуда вы бы просто позвонить, например:

DoStuff<Derived1>(); 
+1

Принято как простейшее решение. Благодарю. –

1

Я внесла несколько исправлений в ваш код, чтобы заставить его работать. Ваш WorkerClass<T> должен также наследовать от класса Base, и вам может потребоваться переопределить вызов DoStuff в вашем суперклассе, если вы используете этот код вместо метода DoStuff в классе Base.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace ConsoleApplication6 
{ 
    public class Base 
    { 
     public virtual void DoStuff(){} 
    } 

    public class Derived1 : Base 
    { 
     public virtual void DoStuff(){} 
    } 

    public class Derived2 : Base 
    { 
     public virtual void DoStuff(){} 
    } 

    public class WorkerClass<T> : Base where T : Base,new() 
    { 
     public WorkerClass() { } 

     public override void DoStuff() 
     { 
      T container = new T(); 
      // do stuff 
     } 
    } 
0

Вы можете использовать covariance, но он поддерживается только на интерфейсах и делегатах. Попробуйте ввести интерфейс IWorkerClass<out T>. Ключевое слово out обозначает шаблон типа T как ковариант.

interface IWorkerClass<out T> 
{ 
    void DoStuff(); 
} 

class WorkerClass<T> : IWorkerClass<T> where T : Base, new() 
{ 
    public void DoStuff() { } 
} 

Затем использовать интерфейс вместо класса в вашем примере кода:

void DoStuff(Type type) 
{ 
    IWorkerClass<Base> worker_class = null; 

    if(type == typeof(Derived1)) 
    { 
     worker_class = new WorkerClass<Derived1>(); // NO compiler error 
    } 
    else if(type == typeof(Derived2)) 
    { 
     worker_class = new WorkerClass<Derived2>(); // NO compiler error 
    } 

    // lots of common code with worker_class 
    worker_class.DoStuff(); 
} 
Смежные вопросы