编译器无法转换约束泛型类型 [英] Compiler fails converting a constrained generic type

查看:131
本文介绍了编译器无法转换约束泛型类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有了一个通用型的G类



在我的类模型,我有



 公共类DetailElement:ElementDefinition 

让我们说我有一个方法像这样

 公共无效DoSomething的< G>(G通用)
其中G:ElementDefinition
{
如果(一般为DetailElement)
{
((DetailElement)通用).DescEN =你好的人; //行1
//////
ElementDefinition元=通用的;
((DetailElement)元素).DescEN =你好再次 // 3号线
//////
(一般为DetailElement).DescEN =你好; // 5号线
}
,否则
{
//做其他的东西
}
}

编译器在第1行报告有一个错误:

 无法转化型'G'到'DetailElement'

不过,3号线工程的罚款。
我可以做写在第5行代码解决此问题。



我想知道的是为什么编译器报告错误在第1行,而不是因为,据我所知,他们是相同的一个在3号线,



编辑:恐怕我可能失踪的框架逻辑的一些重要的一块。



EDIT2:虽然编译器错误的解决方案是很重要的,我的问题是关于为什么编译器第1行,而不是报告错误在第3行。


解决方案

如果被限制为一个 DetailElement 其中G:DetailElement ),那么你可以继续投来ElementDefinition,即(ElementDefinition)通用。但由于可能是另一个子 ElementDefinition DetailElement 在运行时也不会允许它在编译时其中类型是未知的,无法证实的。



在第3行你投的类型的已知的 ElementDefinition 因此,所有你正在做的是上投。编译器不知道这是否会在运行时一个投succcesful但它会出现信任你。编译器并非如此信任的仿制药。



的运营商在第5行也可能返回null,编译器不静态检查,看看它是否在这种情况下的安全类型。您可以使用的类型,而不仅仅是那些与 ElementDefinition 兼容。



从的我可以投,并从泛型参数 的MSDN上:




编译器只会让你隐式转换泛型类型参数对象,或约束指定的类型。



这种隐式转换当然是类型安全的,因为任何不兼容是在编译时发现的。



编译器将让您显式转换泛型类型参数的接口,而不是一类:

 接口ISomeInterface {...} 
类SomeClass的{...}
类MyClass的< T>
{
无效的someMethod(T T)
{
ISomeInterface OBJ1 =(ISomeInterface)吨; //编译
SomeClass的OBJ2 =(SomeClass的)吨; //不能编译
}
}



但是,您可以强制使用临时对象变量从泛型类型参数转换为任何其他类型的

 无效的someMethod< T>(T T)
{对象温度= T;
MyOtherClass OBJ =(MyOtherClass)温度;
}



不用说,这种显式铸造是危险的,因为它可以在抛出异常运行时,如果改为使用泛型类型参数的具体类型不从你明确地转换为类型派生。



而不是冒着铸造异常,更好的方法是使用运营商。在运营商如果泛型类型参数是查询类型,将执行强制转换,如果返回true类型是兼容的,并且将空否则返回。

 公共无效的someMethod(T T)
{
如果(T为int){... }

字符串str = T作为字符串;
如果(STR!= NULL){...}
}



I have a class that has a Generic type "G"

In my class model i have

public class DetailElement : ElementDefinition

Let's say i have a method like this

        public void DoSomething<G>(G generic)
            where G : ElementDefinition
        {
            if (generic is DetailElement)
            {
                ((DetailElement)generic).DescEN = "Hello people"; //line 1
                //////
                ElementDefinition element = generic;
                ((DetailElement)element).DescEN = "Hello again"; //line 3
                //////
                (generic as DetailElement).DescEN = "Howdy"; //line 5
            }
            else
            {
                //do other stuff
            }
        }

Compiler reports one error in line 1:

Cannot convert type 'G' to 'DetailElement'

But line 3 works fine. I can workaround this issue by doing the code written in line 5.

What i would like to know is why does the compiler reports the error in line 1 and not the one in line 3, given that, as far as i know, they are identical.

edit: I am afraid i might be missing some important piece of the framework logic

edit2: Although solutions for the compiler error are important, my question is about why the compiler reports an error on line 1 and not in line 3.

解决方案

If G was constrained to be a DetailElement (where G : DetailElement) then you can go ahead and cast G to ElementDefinition, i.e., "(ElementDefinition) generic". But because G might be another subclass of ElementDefinition other than DetailElement at run-time it won't allow it at compile-time where the type is unknown and unverifiable.

In line 3 the type you cast from is known to be an ElementDefinition so all you're doing is an up-cast. The compiler doesn't know if it will be a succcesful cast at run-time but it will trust you there. The compiler is not so trusting for generics.

The as operator in line 5 might also return null and the compiler doesn't statically check the type to see if it's safe in that case. You can use as with any type, not just ones that are compatible with ElementDefinition.

From Can I Cast to and from Generic Type Parameters? on MSDN:

The compiler will only let you implicitly cast generic type parameters to object, or to constraint-specified types.

Such implicit casting is of course type safe, because any incompatibility is discovered at compile-time.

The compiler will let you explicitly cast generic type parameters to any interface, but not to a class:

   interface ISomeInterface {...}
   class SomeClass {...}
   class MyClass<T> 
    {
      void SomeMethod(T t)
       {
         ISomeInterface obj1 = (ISomeInterface)t;//Compiles
         SomeClass      obj2 = (SomeClass)t;     //Does not compile
       }
    }

However, you can force a cast from a generic type parameter to any other type using a temporary object variable

 void SomeMethod<T>(T t) 
  { object temp = t;
    MyOtherClass obj = (MyOtherClass)temp;  
  }

Needless to say, such explicit casting is dangerous because it may throw an exception at run-time if the concrete type used instead of the generic type parameter does not derive from the type you explicitly cast to.

Instead of risking a casting exception, a better approach is to use the is or as operators. The is operator returns true if the generic type parameter is of the queried type, and as will perform a cast if the types are compatible, and will return null otherwise.

public void SomeMethod(T t)
 {
   if(t is int) {...}

   string str = t as string;
   if(str != null) {...}
 }

这篇关于编译器无法转换约束泛型类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆