Anamika
Anamika

Reputation: 65

Return an object of one class in a generic method

I have a scenario where there are two classes say ClassA and ClassB with methods MethodA and MethodB respectively. I have to write generic method that returns the object instances of the above classes depending on the condition of some integer variable say x. When I try the code below, I get an error that says "Cannot implicitly convert ClassA to T" or "Cannot implicitly convert ClassB to T"

public ClassA
{
    public void MethodA()
    {
        //method implementation
    }
}

public ClassB
{
    public void MethodB()
    {
        //method implementation
    }
}

Generic method as

public T MethodGeneric<T>()
{
    int x;
    ClassA objectA = new ClassA();
    ClassB objectB = new ClassB();

    if(x==2)
    {
        return objectA;
    }
    else
    {
        return objectB;
    }
}

Upvotes: 2

Views: 328

Answers (2)

nawfal
nawfal

Reputation: 73163

From your this double-post which is closed, you're close. You're passing object as type argument, which will return again the same T that is object in your case. That's why you can't use the properties defined on ClassA objects. Instead you should pass the required type like ClassB or ClassC. May be this:

public T getObject<T>(int i) where T : ClassA
{
    if(i == 1)
    {
        ClassB objB = new ClassB();
        return objB as T;
    }
    else
    {
        ClassC objC = new ClassC();
        return objC as T;
    }
}

public static void main()
{
    var obj = getObject<ClassB>(5); //which wont work anyway since i == 5 !!
    obj.aValue = 20;
    obj.bValue = 30;
    //obj.cValue = 40; this wont work since obj is of type ClassB

    //or 

    var obj = getObject<ClassC>(5);
    obj.aValue = 20;
    //obj.bValue = 30; this wont work since obj is of type ClassC now
    obj.cValue = 40; 
}

I'm not sure why you're checking variable int i to decide what's the type that should be returned. That's not a true use of generics. A genuine use of generics might look like:

public T getObject<T>(int i) where T : ClassA
{
    return new T(); //without the use of int i
}

If int i is what decides which object to be returned back, then why use generics at all? You may very well do:

public ClassA getObject(int i)
{
    if(i == 1)
    {
        ClassB objB = new ClassB();
        return objB;
    }
    else
    {
        ClassC objC = new ClassC();
        return objC;
    }
}

public static void main()
{
    var obj = getObject(5);
    if (obj is ClassB)
    {
        obj.aValue = 20;
        obj.bValue = 30;
        //obj.cValue = 40; this wont work since obj is of type ClassB
    }
    //or 

    var obj = getObject(5);
    if (obj is ClassC)
    {
        obj.aValue = 20;
        //obj.bValue = 30; this wont work since obj is of type ClassC
        obj.cValue = 40; 
    }
}

but the catch is you have to check the type from caller side (Main).

And if you want to assign properties bValue and cValue on both ClassB and ClassC objects then you should write these properties in ClassA.

Furthermore you're only using a get accessor, you need set as well to assign values.

Upvotes: 0

Reed Copsey
Reed Copsey

Reputation: 564333

The problem is that T is not ClassA nor ClassB.

You could attempt to handle this via casting, like so:

public static T MethodGeneric<T>() where T : class
{
    int x = 2;
    ClassA objectA = new ClassA();
    ClassB objectB = new ClassB();

    if (x == 2)
    {
        return objectA as T;
    }
    else
    {
        return objectB as T;
    }
}

However, this will not protect you if somebody calls MethodGeneric<ClassC>(), other than returning null in that case.

You could make this safer if you have ClassA and ClassB both derive from the same base class or interface, as you could then put a generic constraint in place that would reduce the chance of error. However, this would still not be a completely safe way of working, as the generics wouldn't be appropriate. It might be better to have an interface implemented by both classes (ie: IClassBase) and then not use generics, but return the interface:

public IClassBase CreateInstance()
{
    //... 
         return objectA; // This will work fine, provided ClassA implements IClassBase
}

Upvotes: 4

Related Questions