c#如何将泛型类型参数强制转换并传递给内部函数?

c#如何将泛型类型参数强制转换并传递给内部函数?,c#,generics,types,parameters,C#,Generics,Types,Parameters,假设我有一个“动物园”移动应用程序。它从在线服务器获取“动物”,并将它们存储在本地数据库中 Class Animal Class Bird : Animal Class Fish : Animal Class Pelican : Bird Class Penguin : Bird 因此,我创建了一个GetAnimalsFromServerService类,该类具有以下函数 public Task<Animal[]> GetAnimalsFromServer<T>() w

假设我有一个“动物园”移动应用程序。它从在线服务器获取“动物”,并将它们存储在本地数据库中

Class Animal
Class Bird : Animal
Class Fish : Animal
Class Pelican : Bird
Class Penguin : Bird
因此,我创建了一个GetAnimalsFromServerService类,该类具有以下函数

public Task<Animal[]> GetAnimalsFromServer<T>() where T : Animal, new() {
    if (typeof(T) == typeof(Bird)) {
        return GetBirdsFromServer<T>();
    } else if (typeof (T) == typeof(Fish)){
        return GetFishFromServer<T>();
    }
}


private Task<Bird[]> GetBirdsFromServer<T>() where T : Bird, new() {
    // Bird specific functionality here.
    if (typeof(T) == typeof(Pelican)) {
        return _serverConnection.GetPelicansFromServer();
    } else if (typeof (T) == typeof(Penguin)){
        return _serverConnection.GetPenguinsFromServer();
    }
}
公共任务GetAnimalsFromServer()其中T:Animal,new(){ 如果(类型(T)=类型(鸟)){ 返回GetBirdsFromServer(); }否则如果(类型(T)=类型(鱼)){ 返回GetFishFromServer(); } } 私有任务GetBirdsFromServer(),其中T:Bird,new(){ //这里有鸟类特有的功能。 if(类型(T)=类型(鹈鹕)){ 返回_serverConnection.GetPelicansFromServer(); }else if(typeof(T)=typeof(Penguin)){ 返回_serverConnection.GetPenguinsFromServer(); } } 这不会编译,因为t的类型为“Animal”,而不是“Bird”(GetBirdsFromServer要求类型为“Bird”)

因为在“if(typeof(T)==typeof(Bird))”检查之后,我知道T是Bird类型的,有没有办法将T转换为Bird

编辑: 根据要求,下面的行不编译

return GetBirdsFromServer<T>();
返回GetBirdsFromServer();
错误是:

类型“T”不能用作泛型类型或方法“GetBirdsFromServer()”中的类型参数“T”。没有从“T”到“Bird”的隐式引用转换

编辑2: 好吧,我想我已经明白为什么这不起作用了。基本上,我最初的问题是“是否有一个我不知道的关键字可以让我做以下等价的事情:

return GetBirdsFromServer<(T as Bird)>();
返回GetBirdsFromServer();
但这是不可能的,因为“as”关键字本质上告诉计算机“哟,这个对象是一只鸟,相信我”。然后,如果它不是一只鸟,计算机可能会像“你撒谎了,那么我就把对象设置为空”

但在这种情况下,计算机没有考虑对象。因此,当你撒谎时,计算机就像“哦,呸,这不是一个对象,我该怎么办?”。因此,由于隔离线不能保证它是一只鸟,因此无法进行某种类型的投射或等效操作。

当你尝试:

return GetBirdsFromServer<T>();

另一件值得一提的事情是,在这种情况下,泛型似乎有点太多(过度设计)。简单的多态继承就足够了。

这里有一种方法可以让您的
GetAnimalsFromServer()
在编译时工作

关键是创建一个包含所有要返回的类型的字典,以及它们作为
Task
返回类型的方法

Dictionary\u getFromServer=newdictionary()
{
{typeof(Pelican),()=>_serverConnection.GetPelicansFromServer().ContinueWith(t=>t.Result.Cast().ToArray())},
{typeof(Penguin),()=>_serverConnection.GetPenguinsFromServer().ContinueWith(t=>t.Result.Cast().ToArray())},
};
然后编写
GetAnimalsFromServer()
方法变得非常简单:

public Task<Animal[]> GetAnimalsFromServer<T>() where T : Animal, new()
{
    if (_getFromServer.ContainsKey(typeof(T)))
    {
        return _getFromServer[typeof(T)]();
    }
    return default(Task<Animal[]>);
}
公共任务GetAnimalsFromServer()其中T:Animal,new() { if(_getFromServer.ContainsKey(typeof(T))) { 返回_getFromServer[typeof(T)](); } 返回默认值(任务); } 我使用以下代码对此进行了测试:

void Main()
{
    GetAnimalsFromServer<Pelican>();
    GetAnimalsFromServer<Penguin>();
}

public class Animal { }

public class Bird : Animal { }

public class Pelican : Bird { }

public class Penguin : Bird { }

public static class _serverConnection
{
    public static Task<Pelican[]> GetPelicansFromServer()
    {
        Console.WriteLine("Got Pelicans");
        return Task.Run(() => new Pelican[] { });
    }
    public static Task<Penguin[]> GetPenguinsFromServer()
    {
        Console.WriteLine("Got Penguins");
        return Task.Run(() => new Penguin[] { });
    }
}
void Main()
{
GetAnimalsFromServer();
GetAnimalsFromServer();
}
公营动物{}
公共类鸟类:动物{}
公共级鹈鹕:鸟{}
公共类企鹅:鸟{}
公共静态类\u服务器连接
{
公共静态任务GetPelicansFromServer()
{
Console.WriteLine(“得到鹈鹕”);
return Task.Run(()=>newpelican[]{});
}
公共静态任务GetPenguinsFromServer()
{
Console.WriteLine(“得到企鹅”);
返回Task.Run(()=>newpenguin[]{});
}
}
当我运行它时,控制台上会显示以下内容:

Got Pelicans Got Penguins 有鹈鹕吗 有企鹅吗
在这种情况下,您可以使用反射来调用
GetBirdsFromServer
,调用所需的
T
-“
”。另外一些问题(
IsAssignableFrom
ContinueWith-Cast
用于向上转换)也已修复:

public Task<Animal[]> GetAnimalsFromServer<T>() where T : Animal, new()
{
    if (typeof(Bird).IsAssignableFrom(typeof(T)))
    {
        var method = GetType().GetMethod(nameof(GetBirdsFromServer));
        var generic = method.MakeGenericMethod(typeof(T));
        var result = generic.Invoke(this, new object[] { });
        return (result as Task<Bird[]>)
                    .ContinueWith(x => x.Result.Cast<Animal>().ToArray());
    }
    //other similar code
}

public Task<Bird[]> GetBirdsFromServer<T>() where T : Bird, new()
{
    // Bird specific functionality here.
    if (typeof(T) == typeof(Pelican))        
        return _serverConnection.GetPelicansFromServer()
                    .ContinueWith(x => x.Result.Cast<Bird>().ToArray());        
    //other similar code
}
公共任务GetAnimalsFromServer()其中T:Animal,new() { if(typeof(Bird).IsAssignableFrom(typeof(T))) { var method=GetType().GetMethod(nameof(GetBirdsFromServer)); var generic=method.MakeGenericMethod(typeof(T)); var result=generic.Invoke(这是一个新对象[]{}); 返回(结果为任务) .ContinueWith(x=>x.Result.Cast().ToArray()); } //其他类似代码 } 公共任务GetBirdsFromServer(),其中T:Bird,new() { //这里有鸟类特有的功能。 if(类型(T)=类型(鹈鹕)) return _serverConnection.GetPelicansFromServer() .ContinueWith(x=>x.Result.Cast().ToArray()); //其他类似代码 } 用法:

var task = probe.GetAnimalsFromServer<Penguin>();
//type of task.Result.FirstOrDefault() will be Animal
//but actual type will be Penguin
var task=probe.GetAnimalsFromServer();
//task.Result.FirstOrDefault()的类型将为
//但实际的类型将是企鹅

您是否有一个带有类型参数的抽象类?如果泛型成员只能按类型工作,那么它是没有意义的。这时您必须区分类型。事实上,泛型成员不应该知道任何可能与泛型约束匹配的类型。这就是泛型约束的全部要点你不应该使用泛型方法,而是应该为每种可能的类型使用不同的方法。如果你需要为每种类型做特定的事情,泛型是错误的工作工具。你试图在这里混合两个概念-泛型和继承。不确定你是否理解。无论如何,不好。忘记泛型,集中精力解决问题这仅通过使用类层次结构实现。关键是,
T
是编译时已知的类型。因此,当您知道编译时的时间时,您也可以调用另一个方法。如果使用
GetAnimalFromServerpublic Task<Animal[]> GetAnimalsFromServer<T>() where T : Animal, new()
{
    if (typeof(Bird).IsAssignableFrom(typeof(T)))
    {
        var method = GetType().GetMethod(nameof(GetBirdsFromServer));
        var generic = method.MakeGenericMethod(typeof(T));
        var result = generic.Invoke(this, new object[] { });
        return (result as Task<Bird[]>)
                    .ContinueWith(x => x.Result.Cast<Animal>().ToArray());
    }
    //other similar code
}

public Task<Bird[]> GetBirdsFromServer<T>() where T : Bird, new()
{
    // Bird specific functionality here.
    if (typeof(T) == typeof(Pelican))        
        return _serverConnection.GetPelicansFromServer()
                    .ContinueWith(x => x.Result.Cast<Bird>().ToArray());        
    //other similar code
}
var task = probe.GetAnimalsFromServer<Penguin>();
//type of task.Result.FirstOrDefault() will be Animal
//but actual type will be Penguin