简体   繁体   中英

Create Generic Class Instance from Static Method in a Derived Class

I have a class in C# with a template and static method similar to

class BClass<T>
{
  public static BClass<T> Create()
  {
    return new BClass<T>();
  }
 }

From this I derive a class and specify a template parameter to the base class

class DClass : BClass<int> { }

A problem occurs when I try to use the static method to create an instance of D

class Program
{
  static void Main(string[] args)
  {
    DClass d = DClass.Create();
  }
}

Gives a compiler error "Cannot implicitly convert type 'Test.BClass<int> ' to 'Test.DClass'."

Adding the below cast leads to a runtime casting exception.

DClass d = (DClass)DClass.Create();

Is there any succint way to allow the static method to create instances of the derived class? Ideally I would like the equivalent of a c++ typedef and I don't want the below syntax (which does work).

BClass<int> d = DClass.Create();

It seems that what you want is for DClass to be an alias for BClass<int> . But that's not what you have here. What you have is that DClass derives from BClass<int> . Thus calling DClass.Create(); creates a BClass<int> , which is not a DClass (it's the other way around).

This might make it clearer. Suppose you had this hierarchy:

class Rectangle {
    static Rectangle Create() {
        return new Rectangle();
    }
}

class Square : Rectangle { }

// code elsewhere
var shape = Square.Create(); // you might want this to return a square,
                             // but it's just going to return a rectangle

One option to get something like the functionality you want might be to define your Create method like this:

static TClass Create<TClass>() where TClass : BClass<T>, new() {
    return new TClass();
}

// code elsewhere
var shape = DClass.Create<DClass>();

That's a bit messy, though (and also requires that you write a parameterless constructor for DClass ). If you're dead set on using a Create method for the instantiation of your objects, consider writing a factory class for it.

Yes it is possible , by having a type reference to the type itself. Note that in the .NET world we are talking of generics, not templates, which do have important differences in the way they work.

class BClass<T, TSelf> where TSelf: BClass<T, TSelf>, new() {
    public static TSelf Create() {
        return new TSelf();
    }
}

class DClass: BClass<int, DClass> {}

class Program {
    static void Main(string[] args) {
        DClass d = DClass.Create();
    }
}
class BClass<T>
    {
        public static T1 Create<T1, T2>() where T1 : BClass<T2>, new()
        {
            return new T1();
        }
    }

    class DClass : BClass<int> { }

    class Program
    {
        static void Main(string[] args)
        {
            DClass d = DClass.Create<DClass, int>();
        }
    }

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