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

use*_*386 5 c# generics parameters types

想象一下,我有一个"动物园"移动应用程序.它从在线服务器获取"Animals"并将它们存储在本地数据库中.

Class Animal
Class Bird : Animal
Class Fish : Animal
Class Pelican : Bird
Class Penguin : Bird
Run Code Online (Sandbox Code Playgroud)

所以我创建了一个具有以下功能的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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这不能编译,因为T的类型为"Animal"而不是Type"Bird"(而GetBirdsFromServer需要类型为"Bird").

因为在"if(typeof(T)== typeof(Bird))"之后我知道T是Bird类型的,有没有办法让我把T作为鸟?

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

return GetBirdsFromServer<T>();
Run Code Online (Sandbox Code Playgroud)

错误是:

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

编辑2:好的,我想我已经理解为什么这不起作用.基本上我原来的问题是"是否有一个我不知道的关键字允许我做相同的:

return GetBirdsFromServer<(T as Bird)>();
Run Code Online (Sandbox Code Playgroud)

但这是不可能的,因为"as"关键字基本上告诉计算机"哟,这个对象是一只鸟,相信我".然后,如果它不是鸟,那么计算机可能就像"你撒谎,我只是将对象设置为null".

但在这种情况下,计算机不考虑对象.因此,当你撒谎时,电脑就像"哦,便便,这不是一个对象,我该怎么做?".因此,由于孤立的线不能保证T是Bird,所以没有办法进行某种类型的转换或等效.

Sla*_*nov 1

在这种情况下,您可以使用反射来调用GetBirdsFromServer所需的T- “ <(T as Bird)>”。其他一些问题(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
}
Run Code Online (Sandbox Code Playgroud)

用法:

var task = probe.GetAnimalsFromServer<Penguin>();
//type of task.Result.FirstOrDefault() will be Animal
//but actual type will be Penguin
Run Code Online (Sandbox Code Playgroud)