开发者

Cannot use polymorphism because of generic base class

I create base generic class with no fields with just one method

public class Base<T> where T:class
{
  public static T Create()
  {
     // create T somehow
  }
}

public class Derived1 : Base<Derived1>
{
}

public class Derived2 : Base<Derived2>
{
}


public class Program
{
    bool SomeFunction()
    {
     // Here I need reference to base class
     Base baseref; // error here 

     switch(somecondition)
     {
       case 1:
        baseref = Derived1.Create();
       break;

       case 2:
        baseref = Derived1.Create();
       break

     }

     // pass baseref somewhere     
    }
}

An obvious option would be converting base class to interface, but this is not possible because interface cannot contain static methods.

I think I need some inter开发者_JS百科mediate base class. Please suggest


You must remove the generic parameter from the Base class, you can move it to just the Create method:

public class Base 
{
    public static T Create<T>() where T : class
    {
        return Activator.CreateInstance<T>();
    }
}

public class Derived1 : Base
{
}

public class Derived2 : Base
{
}


Preliminary Assessment

With this statement,

public class Derived1 : Base<Derived1> {

you're using Derived1 in two different ways according to the base class.

You're effectively telling the C# compiler that Derived1 both:

  1. inherits Base
  2. and Base uses instances of Derived1 through non-inheritance means.

This is not wrong (if that's what you really want), but it's unusual for most programming scenarios; you normally choose one or the other. However the benefit of your logic is: not only do you have an implicit instance of Derived1 through inheritance (same for any other derived class), but the base class can also handle other external instances of that same derived type through the type parameter <T>

One problem I see in the Base class is it turns into a kind of circular scenario when using the factory method as intended, because, to support all derived classes it would need to support something like class Base<T> where T:Base<T>. That's next to impossible to declare because you would have to say in a circular fashion: Base<Base<Base<!!!>>> baseref = null; where !!! represents an infinite number of the same.


One Solution...

One possible (and strong solution) is to move the Type parameter from the class to the factory Create method and restrict its usage to the Base class type like so:

using System;

public abstract class Base 
{
    public static T Create<T>() where T : Base
    {
        return Activator.CreateInstance<T>();
    }

}

Note: I have made the base class abstract which restricts instantiation to the derived types; however you can still use base class references (see switch statement usage below).

These derived classes still inherit from base.

public class Derived1 : Base
{
}

public class Derived2 : Base
{
}

Your factory method is restricted to create only instances of derived types. The logic has been swapped around so the derived type is given to the factory method instead of the factory method being called on it.

public class Program
{
    bool SomeFunction()
    {

    Base baseref = null;

     switch(DateTime.Now.Second)
     {
       case 1:
        baseref = Base.Create<Derived1>();  // OK
       break;

       case 2:
        baseref = Base.Create<Derived2>();  //OK
        break;

       case 60:
        baseref = Base.Create<string>(); //COMPILE ERR - good because string is not a derived class
        break;
     }

     // pass baseref somewhere     
    }
}


public abstract class Base
{
}

public class Base<T> : Base where T : class
{
    public static T Create()
    {
        // create T somehow
    }
}

public class Derived1 : Base<Derived1>    // also inherits non-generic Base type
{
}

public class Derived2 : Base<Derived2>    // also inherits non-generic Base type
{
}


How about creating an interface and having the abstract class implement the interface?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜