user3587754
user3587754

Reputation: 851

Creating a method that returns an object implementing a generic interface

I have a method that is supposed return an object implementing a generic interface. It takes in a parameter that determines which class to instantiate and returns the instantiated object.

    public class PlayerRetriever
    {
        public static IPlayer<T> Retrieve(string SitePath)
        {
            if (SitePath == "Home") { return new Player1(); }
            else { return new AnotherPlayer(); }
        }
    }
    interface IPlayer<T>
    {
        void RunPlayer();
        List<T> RetrievePlayersByMovie(string movie);
    }

Both "Player1" and "AnotherPlayer" implement IPlayer.

Why does my method give me the "type or namespace 'T' could not be found" error under the "T" in my method type?

What is the correct way of writing a method where the return type is an object implementing a generic interface?

Upvotes: 3

Views: 675

Answers (3)

Agrejus
Agrejus

Reputation: 762

In your above code you just missed your generic on PlayerRetriever. It should be PlayerRetriever<T>. To further what you have you can put on constraint on your generic to only take in a type that implements IPlayer. The constraint is where T : IPlayer<T>. If you try to pass in anything that doesn't implement IPlayer it doesn't work. This should be closer to what you are looking for and fixes your original issue.

Also if you want to return a concrete class consider using the Activator in reflection to create your return type. So that would be T myClass = Activator.CreateInstance<T>();

public class PlayerRetriever<T>
    where T : IPlayer<T>
{
    public static IPlayer<T> Retrieve(string SitePath)
    {
        if (SitePath == "Home") { return new Player1(); }
        else { return new AnotherPlayer(); }
    }
}

interface IPlayer<T>
{
    void RunPlayer();
    List<T> RetrievePlayersByMovie(string movie);
}

Upvotes: 0

Michael
Michael

Reputation: 471

If both Player1 and AnotherPlayer implement the IPlayer interface, you don't need to use the generics. If you were passing in the type of object to instantiate rather than the string SitePath you could use reflection to create an object of the required type. The simplest method is as below:

Simply remove the <T> portion on your return type.

public class PlayerRetriever
{
    public static IPlayer Retrieve(string SitePath)
    {
        if (SitePath == "Home") { return new Player1(); }
        else { return new AnotherPlayer(); }
    }
}

If you need to access properties which are specific to an implemention, simply cast it back to the original type:

AnotherPlayer castObject = (AnotherPlayer)returnedValue;

EDIT - Generic Interface Solution

Since your IPlayer<T> interface uses generics the solution would be as follows:

public IPlayer<T> Retrieve<T>(string SitePath)
{
    if (SitePath == "Home") { return new Player1<T>(); }
    else { return new AnotherPlayer<T>(); }
}

And then you would call it like so, but substituting the string type to whatever is required by your code:

IPlayer<string> player = PlayerRetriever.Retrieve<string>("Home");

Upvotes: 4

BFree
BFree

Reputation: 103740

For starters, your Retrieve method needs to be generic like so Retrieve<T>. The problem then becomes, when you call it, you need to specify the type of T. If your Player1 and your AnotherPlayer don't implement the same IPlayer<T> (meaning the T is different), then what will you specify as the type for the generic?

What you can possibly do is, create an IPlayer non generic interface in which you move all the non generic stuff into, and then IPlayer<T> inherits from that one, adding the generic properties/methods. Your method can then return the non generic IPlayer.

Upvotes: 6

Related Questions