2

I have an abstract class which has generic

public abstract class BaseService<T>
{
public abstract void Read(T param);
}

and I have few other classes which is extending this abstract class

public class ServiceOne : BaseService<DTOParam>
{
public override void Read(DTOParam param)
{
//Do something with this DTOParam
}
}

//Other class
public class ServiceTwo : BaseService<DTOParamtwo>
{
public override void Read(DTOParamtwo param)
{
//Do something with this DTOParamtwo
}
}

I have been trying to Instantiate these class like

BaseService<T> bs = new ServiceOne();

which is throwing and error as

Cannot implicitly convert type ServiceOne to BaseService<T>

If you remove the generic it is working fine, What I am missing here? Or is the above approach not possible at all.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
senK
  • 2,782
  • 1
  • 27
  • 38
  • For clarification, what is the class and method that contain the method that won't compile? I can make a good guess as to what's going on but I have to see what the code is to show where/how to change it. – Scott Hannen Jan 06 '18 at 19:18
  • If you strictly need to get that line of code to compile than Scott Hannen's answer get you 95% there, just make the method generic with `where T: BaseService`... Otherwise reading https://stackoverflow.com/questions/1817300/convert-listderivedclass-to-listbaseclass and https://stackoverflow.com/questions/3528821/generics-and-casting-cannot-cast-inherited-class-to-base-class to get some more information about what generics are and aren't. – Alexei Levenkov Jan 06 '18 at 20:05
  • Side note: please avoid adding history inline into the post. If one wants to see what was edited they can just check edit history. – Alexei Levenkov Jan 06 '18 at 20:07

4 Answers4

3

A generic class is a semantic trick, when you instantiate or create a derived from a generic class the compiler creates a different class for each type. Thus, there's no way to cast a derived class which implements a concrete type to a typeless base.

You have two options, cast to the concrete generic type or create an underliying common base (i think the second option is what you really want). To create a common base, in your implementation you would also create on the base a function which accepts an Object as parameter and that function would call to the real generic implementation (see the example below).

Cast to concrete type:

BaseService<DTOParam> bs =  new ServiceOne();

Create a common base:

public abstract class BaseService
{
    public abstract void Read(object parm);
}

public abstract class GenericBaseService<T> : BaseService
{
    public override void Read(object parm)
    {
        Read((T)parm);
    }

    public abstract void Read(T parm);
}

public class ServiceOne : GenericBaseService<DTOParam>
{
    public override void Read(DTOParam param)
    {
        //Do something with this DTOParam
    }
}

//Now you can do:
BaseService srv = new ServiceOne();
srv.Read(dataOnject);
Gusman
  • 14,905
  • 2
  • 34
  • 50
1

The case sensitivity might be an issue. If you have two classes declared, Baseservice<T> and BaseService<T> then you could be using the wrong type.

The problem is likely in the method declaration that contains the statement.

For example, this won't work:

public static BaseService<T> GetService<T>()
{
    BaseService<T> returnValue = new ServiceOne();
    return returnValue;
}

because T could be any type, so you can't assign ServiceOne, which is a BaseService<DTOParam>, to BaseService<T>. What if T is int or some other type? You can't assign BaseService<DTOParam> to BaseService<ItMightBeAnything>.

This, on the other hand, works:

public static BaseService<DTOParam> GetService()
{
    BaseService<DTOParam> returnValue = new ServiceOne();
    return returnValue;
} 
Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
0

You can not create abject and cast at generic type T:

Baseservice bs = new ServiceOne();

should be:

ServiceOne bs = new ServiceOne();

You can later cast bs to base class if you need, but you need and generic type:

Baseservice bs1 = (BaseService<DTOParam>)bs;

Or if you insist on casting on creating instance should be:

Baseservice<DTOParam> bs =  new ServiceOne();
MRsa
  • 666
  • 4
  • 8
  • The non-generic `Baseservice` isn't defined anywhere. `Baseservice` is a generic class so you can't use it without specifying the generic type. – Scott Hannen Jan 06 '18 at 19:14
-2

You have a typo in your code BaseService should be Baseservice:

public class ServiceOne : Baseservice<DTOParam>
{
    public override void Read(DTOParam param)
    {
        //Do something with this DTOParam
    }
}
Benjamin J.
  • 1,239
  • 1
  • 15
  • 28