Por que essa conversão de tipo implícita em C# falha?
-
22-09-2019 - |
Pergunta
Fundo:
Vamos supor que eu tenha a seguinte aula:
class Wrapped<T> : IDisposable
{
public Wrapped(T obj) { /* ... */ }
public static implicit operator Wrapped<T>(T obj)
{
return new Wrapped<T>(obj);
}
public void Dispose() { /* ... */ }
}
Como você pode ver, ele fornece um operador de conversão de tipo implícito para T
→ Wrapped<T>
. Por fim, gostaria de poder usar esta classe da seguinte maneira:
interface IX { /* ... */ }
class X : IX { /* ... */ }
...
IX plainIX = new X();
using (Wrapped<IX> wrappedIX = plainIX)
{
/* ... */
}
Problema:
No entanto, o tipo de conversão no acima using
A cláusula falha. Enquanto eu posso atribuir um new X()
Diretamente a wrappedIX
, Não tenho permissão para atribuir nada do tipo IX
para isso. O compilador reclamará com o seguinte erro:
Erro do compilador CS0266: Não é possível converter implicitamente tipo 'IX' em 'embrulhadou003CIX> '. Existe uma onversão explícita (você está perdendo um elenco?)
Eu não entendo isso. Qual é o problema aqui?
Solução
Eu acredito que é porque IX
é uma interface. O compilador pensa que talvez um valor do tipo IX
já poderia ser derivado de Wrapped<IX>
(ainda que Wrapped<T>
está selado) para que não use a conversão.
Os detalhes são bastante complicados, nas seções 6.4.3 e 6.4.4 da especificação C# 3.0. Basicamente porque IX
é uma interface, não é "abrangida por" quaisquer tipos, o que significa uma etapa posterior em 6.4.4 falha.
Eu sugiro que você crie um tipo não genérico Wrapped
Com este método:
public static Wrapped<T> Of<T>(T item)
{
return new Wrapped<T>(item);
}
Então você pode apenas escrever:
using (Wrapped<IX> wrappedIX = Wrapped.Of(plainIX))
Basicamente, as conversões podem ser um pouco complicadas por várias razões - os métodos simples geralmente são mais fáceis de entender, IMO.