How do I write a function that returns any object derived from a base class in C #?

I have a base class, say A.

From this base class I got a bunch of other classes, say A1, A2, A3 ...

I have a third class, say B. One of the methods it should have should be able to return any class as long as it is derived from A.

I tried the following:

public T getObject<T>() where T : A
{
   return (new A1());
}

      

However, this returns an error that says it cannot convert type A1 to T.

Can this generic return be implemented?

+3


source to share


4 answers


If you know that your class inherits from A, but you don't need to know the exact type, then you don't need generics:

public A getObject()
{
    return new A1();
}

      

If your example was compiled, that would mean that you could call

A2 result = getObject<A2>();

      



But your implementation getObject

always returns new A1()

. Since it A1

does not inherit A2

, this would be wrong.

It looks like you might want to return different types depending on the result of some arcane logic. This is great, there is still no need for generics:

public A getObject()
{
    switch(MysteryLogic())
    {
        case MysteryLogicResult.One:
            return new A1();
        case MysteryLogicResult.Two:
            return new A2();
        case MysteryLogicResult.Three:
            return new A3();
    }
}

      

+2


source


It looks like you need to combine this with a factory:

public interface IAFactory
{
    A Build();
}

      

Then you can change your generic method:

public A getObject<T>() where T : new, IAFactory
{
    return getObject(new T()
}

public A getObject<T>(T factory) where T : IAFactory
{
    return factory.Build();
} 

      

You will need to change your implementation A1, A2:



public class A1 : A, IAFactory
{
   public A1 Build(){
      //Logic for constructing A1
   }
}

      

Or create a dedicated class:

public class A1Factory : IAFactory
{
   public A1 Build(){
      //Logic for constructing A1
   }
}

      

Then you can call your method:

public class Test
{
  public void CallBMethod()
  {
     //option 1
     A option1 = new B().getObject<A1>();

     //option 2
     A option2 = new B().getObject<A1Factory>();

    //Or skip the B.getObject method and access factory directly:
    A a1 = new A1Factory().Build();
    A a2 = new A2Factory().Build();
  }
}

      

+2


source


TL; DR: you must return T because that is the return type for your method.

If you return A1 it looks like it should work as you stated. But you forgot that you can also call the method by going to A2, in which case the return A1 is invalid:

var myObject = getObject<A1>(); // this would have worked
var myObject = getObject<A2>(); // this can not work

      

This will fail because A1 cannot be assigned to type A2. Since the second case can't work, the compiler won't let you do it.

So, the correct way would be to return a new T instead:

public T getObject<T>() where T : A
{
   return (new T());
}

var myObject = getObject<A1>(); // works
var myObject = getObject<A2>(); // also works

      

+1


source


You can use a factory pattern to get the results you want:

public A GetObject (string type) {
     A aObj ;
     if (type == "A1") {
        aobj = new A1 () ;
     else if (type == "A2") {
         aobj = new A2 () ;
     }
     return aObj ;
}

      

+1


source







All Articles