【问题标题】: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:不——这就是问题的重点。请阅读我的回答中引用的博文。

标签: c# generics


【解决方案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 编写的,而不是预先定义和密封的。只是觉得应该提到限制。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-11
相关资源
最近更新 更多