创建一个 returns 实现通用接口的对象的方法

Creating a method that returns an object implementing a generic interface

我有一个方法应该是 return 一个实现通用接口的对象。它接受一个参数,该参数确定要实例化哪个 class 和 return 实例化对象。

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

"Player1" 和 "AnotherPlayer" 都实现了 IPlayer。

为什么我的方法在我的方法类型 "T" 下给出 "type or namespace 'T' could not be found" 错误?

在 return 类型是实现通用接口的对象的情况下,编写方法的正确方法是什么?

首先,您的 Retrieve 方法需要像 Retrieve<T> 这样的通用方法。那么问题就变成了,调用的时候需要指定T的类型。如果您的 Player1AnotherPlayer 没有实现相同的 IPlayer<T>(意味着 T 不同),那么您将指定什么作为泛型的类型?

你可以做的是,创建一个 IPlayer 非通用接口,将所有非通用的东西移入其中,然后 IPlayer<T> 从那个接口继承,添加通用 properties/methods。然后,您的方法可以 return 非泛型 IPlayer.

如果Player1AnotherPlayer都实现了IPlayer接口,则不需要使用泛型。如果您传入要实例化的对象类型而不是字符串 SitePath,则可以使用反射来创建所需类型的对象。最简单的方法如下:

只需删除 return 类型上的 <T> 部分。

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

如果您需要访问特定于某个实现的属性,只需将其转换回原始类型即可:

AnotherPlayer castObject = (AnotherPlayer)returnedValue;

编辑 - 通用接口解决方案

由于您的 IPlayer<T> 接口使用泛型,因此解决方案如下:

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

然后您可以这样称呼它,但是将 string 类型替换为您的代码所需的任何类型:

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

在上面的代码中,您只是错过了 PlayerRetriever 上的泛型。应该是PlayerRetriever<T>。为了进一步扩展你所拥有的,你可以对你的泛型进行限制,使其只接受实现 IPlayer 的类型。约束是 where T : IPlayer<T>。如果您尝试传递任何未实现 IPlayer 的东西,它就不起作用。这应该更接近您正在寻找的内容并修复了您的原始问题。

此外,如果您想 return 一个具体的 class 考虑使用 Activator 反射来创建您的 return 类型。那就是 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);
}