简体   繁体   中英

How can I convert Class<Derived> to Class<Base>?

I have a base class with multiple derived classes:

class Base { }

class Derived1 : Base { }

class Derived2 : Base { }

Then I have a worker class that takes this class as a generic type:

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

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

The problem is when I instantiate WorkerClass, I only have the type as a variable. I would like to do this:

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();
}

But the compiler complains about implicitly casting WorkerClass<Derived> to WorkerClass<Base> . Explicitly casting gives an error as well. The compiler suggests defining public static implicit operator WorkerClass<T>(WorkerClass<Derived>) , but I'm not sure what that code would look like. I could obviously put all the logic inside the if-else, but that seems needlessly repetitive.

I may be misreading your intent, but I would think you could do something like this using generics with constraints:

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

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

From there you would simply call, for example:

DoStuff<Derived1>();

I made several corrections to your code to get it to work. Your WorkerClass<T> needs to inherit from the Base class as well and you may need to override the DoStuff call in your super class if you that code to be executed instead of the DoStuff method in the Base class.

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
        }
    }

You could use covariance , but it is only supported on interfaces and delegates. Try introducing the interface IWorkerClass<out T> . The out keyword marks the template type T as covariant.

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

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

Then use the interface instead of the class in your code example:

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();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM