Me pregunto si dynamic
es semánticamente equivalente a object
cuando se utiliza como un parámetro de tipo genérico. Si es así, tengo curiosidad por saber por qué existe esta limitación, ya que ambas son diferentes cuando se asignan valores a variables o parámetros formales.¿Por qué "dinámico" no es covariante y contravariante con respecto a todos los tipos cuando se usa como parámetro de tipo genérico?
He escrito un pequeño experimento en C# 4.0 para desvelar algunos de los detalles. He definido algunas interfaces e implementaciones simples:
interface ICovariance<out T> { T Method(); }
interface IContravariance<in T> { void Method(T argument); }
class Covariance<T> : ICovariance<T>
{
public T Method() { return default(T); }
}
class Contravariance<T> : IContravariance<T>
{
public void Method(T argument) { }
}
Los detalles interesantes del experimento:
class Variance
{
static void Example()
{
ICovariance<object> c1 = new Covariance<string>();
IContravariance<string> c2 = new Contravariance<object>();
ICovariance<dynamic> c3 = new Covariance<string>();
IContravariance<string> c4 = new Contravariance<dynamic>();
ICovariance<object> c5 = new Covariance<dynamic>();
IContravariance<dynamic> c6 = new Contravariance<object>();
// The following statements do not compile.
//ICovariance<string> c7 = new Covariance<dynamic>();
//IContravariance<dynamic> c8 = new Contravariance<string>();
// However, these do.
string s = new Covariance<dynamic>().Method();
new Contravariance<string>().Method((dynamic)s);
}
}
Los primeros dos estados con c1
y c2
demuestran que la covarianza básica y contravarianza están trabajando. Luego uso c3
y c4
para mostrar que dynamic
se puede usar como un parámetro de tipo genérico de la misma manera.
Las declaraciones con c5
y c6
revelan que una conversión de dynamic
a object
es siempre válida. Esto no es realmente sorprendente, ya que object
es un antepasado de todos los demás tipos.
El experimento final con c7
y c8
es donde empiezo a confundirme. Implica que los métodos que devuelven los objetos dynamic
no son sustitutos de los métodos que devuelven string
, y de manera similar que los métodos que aceptan objetos string
no pueden tomar dynamic
. Las dos declaraciones finales con la asignación y la llamada al método muestran que claramente este no es el caso, de ahí mi confusión.
pensé en esto un poco, y se preguntó si esto es para evitar que los programadores de usar ICovariance<dynamic>
como un escalón entre las conversiones de tipos que puedan resultar en errores de ejecución, tales como:
ICovariance<dynamic> c9 = new Covariance<Exception>();
ICovariance<string> c10 = c9;
// While this is definitely not allowed:
ICovariance<string> c11 = new Covariance<Exception>();
Sin embargo, esto es poco convincente en el caso de dynamic
desde perdemos seguridad de tipos de todos modos:
dynamic v1 = new Exception();
string v2 = v1;
Dicho de otra manera, la pregunta es "¿por qué la semántica de dynamic
difieren entre asignación y covarianza/contravarianza con los genéricos? "
espero que Eric nos visite y nos dé revelaciones :) – Andrey
Estoy lanzando 'Summon Eric Lippert' tan fuerte como puedo. – Amy
deberías decir "Casting 'Summon Eric Lippert' tan fuerte como puedo." – Andrey