C# 将返回值强制转换为泛型类型

C# 将返回值强制转换为泛型类型,c#,generics,C#,Generics,假设我们有一个带有单个泛型方法的接口: public interface IExtender { T GetValue<T>(string tag); } 公共接口IExtender { T GetValue(字符串标记); } 以及它的一个简单实现a,它根据“tag”参数返回两种不同类型(B和C)的实例: public class A : IExtender { public T GetValue<T>(string tag) {

假设我们有一个带有单个泛型方法的接口:

public interface IExtender
{
    T GetValue<T>(string tag);
}
公共接口IExtender
{
T GetValue(字符串标记);
}
以及它的一个简单实现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);
    }
}
公共A类:IExtender
{
公共T GetValue(字符串标记)
{
if(typeof(T)=typeof(B)&&tag==null)
返回(T)(对象)新的B();
if(typeof(T)=typeof(C)&&tag==“foo”)
返回(T)(对象)新C();
返回默认值(T);
}
}
是否可以避免双重强制转换
(T)(对象)
?或者,有没有一种方法可以告诉编译器“嘿,我确信这个强制转换在运行时不会失败,让我在不首先强制转换到对象的情况下执行它!”

或者,有没有一种方法可以告诉编译器“嘿,我确信这个强制转换在运行时不会失败,让我在不首先强制转换到对象的情况下执行它!”

不,语言是故意设计来防止这种情况发生的。埃里克·利珀特。我同意这很烦人,但确实有一定的道理


老实说,像这样的“通用”方法通常有点设计味道。如果一个方法必须具有不同类型的特殊情况,那么至少应该考虑使用单独的方法。(
GetB
GetC

不,这是不可能的。唯一的方法是让编译器知道关于
T
的附加假设。正如所证明的,C中没有定义任何约束来要求特定类型转换的可用性。

如果让B和C实现相同的接口,您可以在
T
上使用a。也许不完全是你想要的,但正如其他人所建议的那样,你想要的其实是不可能的

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);
    }
}
公共接口IclassBndC{}
公共B类:IclassBandC{}
公共C类:IclassBandC{}
公开A类:IExtender
{
公共T GetValue(字符串标记),其中T:IclassBandC
{
if(标记==null)
返回新的B();
如果(标记==“foo”)
返回新的C();
返回默认值(T);
}
}
检查此示例:

    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);
    }
public T GetValue(字符串标记),其中T:class,new()
{
if(typeof(T)=typeof(B)&&tag==null)
返回新的T();
if(typeof(T)=typeof(C)&&tag==“foo”)
返回新的T();
返回默认值(T);
}
不需要强制转换,您可以创建“T”的实例,只需添加泛型约束,说明T是一个类,并且它具有无参数构造函数,这样您就不需要创建另一个基类型,并且您可以确保只有合适的类型将通过此泛型方法。

public T MyMethod(字符串标记),其中T:class
public T MyMethod<T>(string tag) where T : class
    {
        return new A() as T;
    }
{ 将新的A()返回为T; }
您可以使用dynamic来存储实际结果,但必须确保泛型参数类型是您返回的正确类型

TResult GetResult<TResult>() 
{
    dynamic r = 10;
    return r;
}
TResult GetResult()
{
动态r=10;
返回r;
}

为什么需要(T)(对象)转换?你可以直接(T)新的C()对吗?@Anuraj:不,这就是问题的关键所在。请阅读我在回答中引用的博客文章。注意,这要求您可以修改
B
C
@O.R.Mapper true,我是否遗漏了一点不可能的内容?您没有,但没有提到
B
C
是由OP编写的,而不是预定义和密封的。我认为应该提到限制。好吧,这就是当你(我,真的)试图简化代码以作为示例发布时发生的情况。在实际的代码中,实例已经存在,我不能对t施加任何约束。所以,是的,这是可行的(谢谢!),但不能解决我的问题。是的。GetB、GetC和GetEtc在这里不是一个选项,但我不知道这是否是详细讨论设计的正确地方。无论如何,第一段和链接是我一直在寻找的答案。谢谢。是的,这是可能的,在不止一个方面,有时它是解决设计问题的唯一好方法。这就是为什么引入了动态关键字。还有Convert.ChangeType。@DinoDini:我认为这两个都没有真正做到OP所说的。OP不想执行任何实际值转换-他们只是想避免双重强制转换。有效地使用dynamic只会使到
对象的转换隐式化,但它不会以任何有用的方式删除它。使用dynamic cast是可能的。实际答案是。在这一页的底部。同样,这并没有真正删除强制转换-它只是使其隐式而不是显式。它的表现也可能不如双重演员。这正是我想要的!