2009-06-22 6 views

Respuesta

19

Los operadores de conversión no pueden ser genéricos. Desde la sección de especificaciones 10.10, aquí está el formato de una conversión de operador-declarador:

conversion-operator-declarator: 
    implicit operator type ( type identifier ) 
    explicit operator type ( type identifier )

Compare esto con, por ejemplo, un método de cabecera:

método de cabecera : atributos opt método modificadores opt parciales opt de tipo de retorno -Nombre de usuario tipo de parámetro lista opt ( de parámetros formales lista opt) tipo parámetros que se limitaciones de cláusulas opt

(Disculpa el formato - no estoy seguro de cómo hacerlo apostar ter.)

Tenga en cuenta que el formato del operador no incluye una lista de parámetros de tipo ni escribe restricciones de parámetros.

+2

E incluso si admitimos conversiones genéricas definidas por el usuario, esta seguiría siendo ilegal. Es ilegal definir una conversión que reemplace una conversión incorporada. Esto sería así si T y U fueran del mismo tipo; estarías reemplazando la conversión de identidad. –

+1

Como los moldes son decididos por el compilador, si T y U son del mismo tipo, entonces no usarían el molde definido por el usuario, y serían legales. –

2

Su código se reduce a la línea: return new Foo<U>((U)a.Item)

Cuando intenta asignar una clase base para una clase heredada, que es imposible.

Digamos T (clase base) es de tipo Stream y U es de tipo MemoryStream (clase heredada), no se puede asignar un Stream a una variable de tipo MemoryStream.

+0

Claro que sí, si la referencia enmascara el objeto como una secuencia, pero de hecho es un MemoryStream, entonces ciertamente puede convertirlo a una secuencia de memoria. Este es un método legítimo, el problema es que no se pueden especificar restricciones genéricas en una sobrecarga del operador ... – LaserJesus

+0

... Si toma el código que tengo y lo expresa como un método en lugar de una sobrecarga del operador, compilará – LaserJesus

0

Parece que desea una conversión contravariant, pero struct s son inmutables, la conversión no le compra nada, simplemente puede decir new Foo<U>((U)a.Item) como @Gidon ha señalado.

Si se considera a cambiar Foo a ser una clase, entonces podemos hacer alguna diferencia:

public interface IFoo<in T> { 
    T Item { 
     set; 
    } 
} 

public class Foo<T>:IFoo<T> { 
    public Foo(T item) { 
     this.Item=item; 
    } 

    public T Item { 
     get; set; 
    } 

    // public static explicit operator Foo<U>(U a) { 
    // return new Foo<U>((U)a.Item); 
    // } 
} 

y usarlo como:

var foo = new Foo<object>(new object { }); 
IFoo<String> bar = foo; 
bar.Item="123"; 
var b = Object.ReferenceEquals(foo, bar); // true 

Por cierto, la variación en las interfaces genéricas es solo disponible desde .netfx 4.0.

Cuestiones relacionadas