Мне интересно, если dynamic
является семантически эквивалентным object
при использовании в качестве параметра типового типа. Если это так, мне любопытно, почему это ограничение существует, поскольку они различаются при назначении значений переменным или формальным параметрам.
Я написал небольшой эксперимент в С# 4.0, чтобы разделить некоторые детали. Я определил некоторые простые интерфейсы и реализации:
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) { }
}
Интересные подробности эксперимента:
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);
}
}
Первые два оператора с c1
и c2
демонстрируют, что основная ковариация и контравариантность работают. Затем я использую c3
и c4
, чтобы показать, что dynamic
может использоваться как общий тип типа таким же образом.
Операторы с c5
и c6
показывают, что всегда выполняется преобразование с dynamic
в object
. Это не слишком удивительно, так как object
является предком всех других типов.
Последний эксперимент с c7
и c8
заключается в том, что я начинаю запутываться. Это означает, что методы, возвращающие объекты dynamic
, не заменяют методы, возвращающие теги string
, и аналогично, что методы, которые принимают объекты string
, не могут принимать теги dynamic
. Последние два утверждения с вызовом присваивания и метода показывают, что это явно не так, поэтому моя путаница.
Я немного подумал об этом и задался вопросом, не препятствует ли программистам использовать ICovariance<dynamic>
в качестве шага между преобразованиями типов, что приведет к ошибкам во время выполнения, например:
ICovariance<dynamic> c9 = new Covariance<Exception>();
ICovariance<string> c10 = c9;
// While this is definitely not allowed:
ICovariance<string> c11 = new Covariance<Exception>();
Однако это неубедительно в случае dynamic
, поскольку мы все равно теряем безопасность типов:
dynamic v1 = new Exception();
string v2 = v1;
Иными словами, вопрос "Почему семантика dynamic
отличается от назначения и ковариации/контравариантности с дженериками?"