繁体   English   中英

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

[英]c# How do I cast and pass a generic type parameter to an internal function?

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

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

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

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

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

return GetBirdsFromServer<T>();

错误是:

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

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

return GetBirdsFromServer<(T as Bird)>();

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

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

以下是解决此问题的方法,以使GetAnimalsFromServer<T>()在编译时工作。

关键是要创建一个包含要返回的所有类型的字典,以及将这些类型作为Task<Animal[]>返回的方法。

Dictionary<Type, Func<Task<Animal[]>>> _getFromServer = new Dictionary<Type, Func<Task<Animal[]>>>()
{
    { typeof(Pelican), () => _serverConnection.GetPelicansFromServer().ContinueWith(t => t.Result.Cast<Animal>().ToArray()) },
    { typeof(Penguin), () => _serverConnection.GetPenguinsFromServer().ContinueWith(t => t.Result.Cast<Animal>().ToArray()) },
};

然后编写GetAnimalsFromServer<T>()方法变得非常简单:

public Task<Animal[]> GetAnimalsFromServer<T>() where T : Animal, new()
{
    if (_getFromServer.ContainsKey(typeof(T)))
    {
        return _getFromServer[typeof(T)]();
    }
    return default(Task<Animal[]>);
}

我用以下代码测试了这个:

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[] { });
    }
}

当我运行它时,我在控制台上得到以下内容:

Got Pelicans
Got Penguins

在这种情况下,您可以使用反射来调用带有所需TGetBirdsFromServer ” - “ <(T as Bird)> ”。 另一个问题( IsAssignableFromContinueWith - Cast for upcasting)也是固定的:

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
}

用法:

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

当你尝试:

return GetBirdsFromServer<T>();

你基本上说你需要从Animal类型的服务器中获取鸟类。 但是你在GetBirdsFromServer中将T定义为继承Bird的类。 你对那次回归做了什么就像动物(T)继承自伯德。

您需要做的是制定某种策略/工厂,以获得您想要的响应。 例如:

return GetBirdsFromServer<Pelican>();

另外值得一提的是,在这种情况下,仿制药看起来有点太多了(过度设计)。 具有多态性的简单继承应该足够了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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