将返回值转换为泛型类型
Posted
技术标签:
【中文标题】将返回值转换为泛型类型【英文标题】:Casting return value to a generic type 【发布时间】:2021-05-31 06:56:54 【问题描述】:假设我们有一个带有单个泛型方法的接口:
public interface IExtender
T GetValue<T>(string tag);
以及它的一个简单实现 A,它根据“tag”参数返回两种不同类型(B 和 C)的实例:
public class A : IExtender
public T GetValue<T>(string tag)
if (typeof(T) == typeof(B) && tag == null)
return (T)(object) new B();
if (typeof(T) == typeof(C) && tag == "foo")
return (T)(object) new C();
return default(T);
是否可以避免双重演员(T)(object)
?或者,有没有办法告诉编译器“嘿,我确信这个转换在运行时不会失败,让我在不先转换为对象的情况下完成它!”
【问题讨论】:
为什么需要 (T)(Object) 转换?你可以直接 (T) new C() 对吧? @Anuraj:不——这就是问题的重点。请阅读我的回答中引用的博文。 【参考方案1】:或者,有没有办法告诉编译器“嘿,我确信这个转换在运行时不会失败,让我在不先转换为对象的情况下完成它!”
不,该语言是故意设计来防止这种情况的。埃里克·利珀特blogged about this recently。我同意这很烦人,但确实有某种意义。
说实话,像这样的“通用”方法通常有点设计味道。如果一个方法必须有各种不同类型的特殊情况,您至少应该考虑使用单独的方法。 (GetB
, GetC
)
【讨论】:
是的。 GetB、GetC 和 GetEtc 不是这里的选项,但我不知道这是否适合详细讨论设计。无论如何,第一段和链接是我正在寻找的答案。谢谢。 是的,它是可能的,不止一种方式,有时它是解决设计问题的唯一好方法。这就是引入动态关键字的原因。和 Convert.ChangeType. @DinoDini:我不认为其中任何一个实际上都在做 OP 所说的事情。 OP 不 想要 执行任何实际值转换 - 他们只是想避免双重转换。有效地使用动态只会使转换为object
隐式,但不会以任何有用的方式将其删除。【参考方案2】:
public T MyMethod<T>(string tag) where T : class
return new A() as T;
【讨论】:
正是我想要的!【参考方案3】:检查此示例:
public T GetValue<T>(string tag) where T : class, new()
if (typeof(T) == typeof(B) && tag == null)
return new T();
if (typeof(T) == typeof(C) && tag == "foo")
return new T();
return default(T);
不需要强制转换,您可以创建“T”的实例,只需添加通用约束,说明 T 是一个类并且它具有无参数构造函数,因此您不需要创建另一个基类型,您可以确定只有合适的类型才会通过这个泛型方法。
【讨论】:
嗯,当你(我,真的)尝试简化代码以作为示例发布时,就会发生这种情况。在实际代码中,实例已经存在,我不能对 T 施加任何限制。所以是的,这有效(谢谢!)但不能解决我的问题。【参考方案4】:您可以使用动态来存储您的真实结果,但您必须确保泛型参数类型是您返回的正确类型。
TResult GetResult<TResult>()
dynamic r = 10;
return r;
【讨论】:
实际答案。在页面的底部。再次。 这并没有真正删除演员表 - 它只是使其隐式而不是显式。它的表现也可能不如双重演员。 这对我来说确实是一种解决方法。如果程序员自己检查类型,我看不到问题。【参考方案5】:不,这是不可能的。这样做的唯一方法是让编译器知道关于T
的其他假设。正如the list of generic parameter constraints 所证明的那样,C# 中没有定义要求特定演员表的可用性的约束。
【讨论】:
动态转换是可能的。【参考方案6】:如果您让 B 和 C 实现相同的接口,您可以在 T
上使用 type constraint。可能不完全是您想要的,但正如其他人所建议的那样,您想要的实际上是不可能的。
public interface IclassBndC
public class B : IclassBandC
public class C : IclassBandC
public class A : IExtender
public T GetValue<T>(string tag) where T : IclassBandC
if (tag == null)
return new B();
if (tag == "foo")
return new C();
return default(T);
【讨论】:
注意,这要求你可以修改B
和C
。
@O.R.Mapper 是的,我是否错过了不可能的提法?
你没有,但也没有提到 B
和 C
是由 OP 编写的,而不是预先定义和密封的。只是觉得应该提到限制。以上是关于将返回值转换为泛型类型的主要内容,如果未能解决你的问题,请参考以下文章
无法将类型“Int”的值转换为泛型中的预期参数类型“Int”