Рассмотрим следующий (сильно упрощенный) код:
public T Function<T>() {
if (typeof(T) == typeof(string)) {
return (T) (object) "hello";
}
...
}
Это абсурдно - сначала привести к object
, а затем к T
. Но компилятор не может знать, что предыдущий тест гарантировал, что T
имеет тип string
.
Какой самый элегантный идиоматичный способ достижения этого поведения в C # (который включает в себя избавление от глупого typeof(T) == typeof(string)
, поскольку T is string
не может использоваться)?
Приложение: В .net нет дисперсии возвращаемого типа, поэтому вы не можете сделать перегрузку функции для ввода строки (что, кстати, является лишь примером, но одной из причин, почему ассоциация конец переопределения в полиморфизме, например, UML, не может быть сделано в c #). Очевидно, было бы замечательно следующее, но это не работает:
public T Function<T>() {
...
}
public string Function<string>() {
return "hello";
}
Конкретный пример 1: Поскольку было несколько атак на тот факт, что универсальная функция, которая проверяет определенные типы, не является универсальной, я попытаюсь привести более полный пример. Рассмотрим шаблон дизайна Type-Square. Вот следующий фрагмент:
public class Entity {
Dictionary<PropertyType, object> properties;
public T GetTypedProperty<T>(PropertyType p) {
var val = properties[p];
if (typeof(T) == typeof(string) {
(T) (object) p.ToString(this); // magic going here
}
return (T) TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(val);
}
}
Конкретный пример 2: Рассмотрим шаблон проектирования интерпретатора:
public class Expression {
public virtual object Execute() { }
}
public class StringExpression: Expression {
public override string Execute() { } // Error! Type variance not allowed...
}
Теперь давайте используем дженерики в Execute, чтобы позволить вызывающей стороне принудительно возвращать тип:
public class Expression {
public virtual T Execute<T>() {
if(typeof(T) == typeof(string)) { // what happens when I want a string result from a non-string expression?
return (T) (object) do_some_magic_and_return_a_string();
} else if(typeof(T) == typeof(bool)) { // what about bools? any number != 0 should be True. Non-empty lists should be True. Not null should be True
return (T) (object) do_some_magic_and_return_a_bool();
}
}
}
public class StringExpression: Expressiong {
public override T Execute<T>() where T: string {
return (T) string_result;
}
}