将返回值转换为泛型类型

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

【讨论】:

注意,这要求你可以修改BC @O.R.Mapper 是的,我是否错过了不可能的提法? 你没有,但也没有提到 BC 是由 OP 编写的,而不是预先定义和密封的。只是觉得应该提到限制。

以上是关于将返回值转换为泛型类型的主要内容,如果未能解决你的问题,请参考以下文章

将返回值转换为泛型类型

无法将类型“Int”的值转换为泛型中的预期参数类型“Int”

201671010113 2016-2017-2 《JAVA程序设计》第十周

使用反射为泛型类创建构造函数

Java泛型详解

java中的泛型方法