简体   繁体   中英

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?

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 .

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");

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM