3

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?

3
  • 2
    How is the compiler supposed to figure out what T is? You need to either give it that information when you call it by making it public static IPlayer<T> Retrieve<T>(string SitePath) or you need to return something non-generic. Commented Jan 29, 2015 at 20:45
  • Is the T type you're using on Player1 and AnotherPlayer connected by a hierarchy? Commented Jan 29, 2015 at 21:04
  • @ClaudioRedi No, there's no connection to both of those classes' T types Commented Jan 29, 2015 at 21:10

3 Answers 3

6

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.

Sign up to request clarification or add additional context in comments.

Comments

4

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

3 Comments

When I remove the T portion I get a "Using the generic type 'IPlayer<T>' requires 1 type arguments" error. I think that might be because my interface is a generic interface?
Yes it will be. Is it possible for you to update your question and show your interface?
I have updated my answer with what I think will work in your situation. Without seeing the full interface definition I cannot be sure, but this compiles and runs for me.
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.