想象一下我有一个“动物园”移动应用。它从在线服务器上获取“动物”并将其存储在本地数据库中。
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的类型为“动物”,而不是类型为“鸟”(并且GetBirdsFromServer要求类型为“鸟”)。
自从经过“ if(typeof(T)== typeof(Bird))”检查之后,我知道T是Bird类型,是否有办法将T转换为Bird?
编辑: 根据要求,以下行无法编译
return GetBirdsFromServer<T>();
错误是:
类型'T'不能用作通用类型或方法'GetBirdsFromServer()'中的类型参数'T'。没有从“ T”到“ Bird”的隐式引用转换
编辑2: 好吧,我想我对为什么这行不通了。本质上,我最初的问题是“是否有一个我不知道的关键字,该关键字使我可以执行以下操作:
return GetBirdsFromServer<(T as Bird)>();
但这是不可能的,因为关键字“ as”实际上告诉计算机“哟,这个对象是鸟,请相信我”。然后,如果它不是鸟,那么计算机可能会像“您撒谎了,然后将对象设置为null”。
但是在这种情况下,计算机没有考虑物体。因此,当您说谎时,计算机就像“哦,大便,这不是对象,我要做什么?”。因此,由于孤立的行不能保证T是Bird,因此无法进行某种类型的强制转换或等效操作。
答案 0 :(得分:1)
这里有一种解决方法,可以使您的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
答案 1 :(得分:1)
在这种情况下,您可以使用反射来使用所需的publish the build to App Store from website
-“ 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
}
答案 2 :(得分:0)
尝试时:
return GetBirdsFromServer<T>();
您基本上说您需要从Animal
类型的服务器中获取鸟。但是您在GetBirdsFromServer
中将T定义为继承Bird
的类。您使用该收益所做的就像是Animal(T)继承自Bird一样。
您需要做的是制定某种策略/工厂,以获取所需的响应。例如:
return GetBirdsFromServer<Pelican>();
值得一提的另一件事是,在这种情况下,泛型似乎太多了(超出设计)。具有多态性的简单继承就足够了。