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