Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return Type T in interface in C#?

I have an interface like this:

public interface IUser{
    //some properties here

    T ToDerived(User u);
}

I'm new to interface development, so here's what I'm trying to accomplish. I will have a base class

public class User 

that does NOT implement the above interface. Then I will have a derived class

SalesUser : User, IUser
{
    //no properties needed because they exist in the User class

    SalesUser ToDerived(User u)
    {
        //code for converting a base User to a derived SalesUser
    }
}

I would like to write the function for ToDerived(User u) in the SalesUser class, but in the interface, I do not know how to define this as the ToDerived method declaration that I have now in the interface is not compiling.

I hope this makes sense.

like image 715
jaressloo Avatar asked Apr 09 '12 18:04

jaressloo


People also ask

Does interface have return type?

An interface name can also be used as a return type but the returned object must implement methods of that interface. The following Java program shows the implementation of a class name as a return type. In the above code, a SumResult class contains an addition method with class name as its return type.

What does the T mean in C#?

T is called type parameter, which can be used as a type of fields, properties, method parameters, return types, and delegates in the DataStore class. For example, Data is generic property because we have used a type parameter T as its type instead of the specific data type. Note.

CAN interfaces have generics?

Generic interfaces can inherit from non-generic interfaces if the generic interface is covariant, which means it only uses its type parameter as a return value.

How can use generics with interface in C#?

You can declare variant generic interfaces by using the in and out keywords for generic type parameters. ref , in , and out parameters in C# cannot be variant. Value types also do not support variance. You can declare a generic type parameter covariant by using the out keyword.


2 Answers

public interface IUser<T> where T : User
{
    //some properties here

    T ToDerived(User u);
}

SalesUser : User, IUser<SalesUser>
{
    //no properties needed because they exist in the User class

    SalesUser ToDerived(User u)
    {
        //code for converting a base User to a derived SalesUser
    }
}

Not sure this is what you want, but I added a generic type constraint on the interface to ensure that the generic type is User or inherits from it.

like image 82
Oded Avatar answered Oct 17 '22 06:10

Oded


The answer by Oded solves the compilation problem, allowing you to define the ToDerived method that satisfies the interface. However, as I stated in the comment, I'm not exactly sure this is the best implementation.

The main problem I have with it is that conversion methods like this are normally needed in a static context. You don't have an instance of a SalesUser; you want one, and have a User, so you call the method in static context (SalesUser.ToDerived(myUser)) and you get a SalesUser (the method would be more appropriately named FromUser() or similar). The method you specify in the interface requires you to already have a SalesUser in order to convert a User to a SalesUser. The only situation I can think of in which you really would need a pre-existing SalesUser is for a "partial clone"; you are making a new SalesUser instance using information from both the User passed in and from the SalesUser on which you are calling the method. In all other cases, you either don't need a SalesUser (conversions, which should be static as mentioned), or you don't need a User (a "clone" or "deep copy" method that produces a new instance with the same data as the instance on which you called the method).

Also, consumers of your class have to know that they must call ToDerived() in order to perform the conversion from a User to a SalesUser. Normally, a C# programmer would expect an explicit or implicit conversion to be available:

public class SalesUser
{

    public static explicit operator (User user)
    {
        //perform conversion of User to SalesUser
    }

}

//the above operator permits the following:
mySalesUser = (SalesUser)myUser;

... OR, failing a conversion operator, one would expect to be able to construct a SalesUser using a User:

public class SalesUser:IUser
{
   public SalesUser(User user)
   {
      //initialize this instance using the User object
   }
}

//the above allows you to do this:
mySalesUser = new SalesUser(myUser);

//and it also allows the definition of a method like this,
//which requires the generic to be an IUser and also requires a constructor with a User
public void DoSomethingWithIUser<T>(User myUser) where T:IUser, new(User)
{ 
    //...which would allow you to perform the "conversion" by creating a T:
    var myT = new T(myUser);
}

Now, static members do not satisfy interface definitions, and interfaces cannot define static members or constructor signatures. This tells me that the IUser interface should not try to define the conversion method; instead, methods that need an IUser of some sort can simply specify that, and the user can provide an implementation as necessary without the implementation needing to know it can convert to itself.

like image 39
KeithS Avatar answered Oct 17 '22 04:10

KeithS