Допустим, мы имеем следующие классы:Использование универсального типа передается без ограничений с ограничениями общего типа
public interface IFrobnicator<T> { }
class ComparableFrobnicator<T> : IFrobnicator<T> where T : IComparable<T>
{
public ComparableFrobnicator(T value) { }
}
class EquatableFrobnicator<T> : IFrobnicator<T> where T : IEquatable<T>
{
public EquatableFrobnicator(T value) { }
}
Вы можете написать методы
public IFrobnicator<T> MakeFrobnicatorFromComparable<T>(T value) where T : IComparable<T>
{
return new ComparableFrobnicator<T>(value);
}
public IFrobnicator<T> MakeFrobnicatorFromEquatable<T>(T value) where T : IEquatable<T>
{
return new EquatableFrobnicator<T>(value);
}
Если бы я хотел, чтобы объединить это в один метод, наиболее очевидный способ не скомпилируется:
public IFrobnicator<T> MakeFrobnicator<T>(T value)
{
if (value is IComparable<T>)
{
return new ComparableFrobnicator<T>(value);
}
else if (value is IEquatable<T>)
{
return new EquatableFrobnicator<T>(value);
}
else throw new ArgumentException();
}
Это вызывает следующую ошибку при компиляции led:
CS0314 Тип 'T' не может использоваться как параметр типа 'T' в общем типе или методе 'UserQuery.ComparableFrobnicator'. Нет конверсии бокса или преобразования параметров типа из «T» в «System.IComparable».
Я не могу заменить new ComparableFrobnicator <T>
с new ComparableFrobnicator<IComparable<T>>
потому, что вызывает проблемы по линии с получением value
обратно - вы не можете отбрасывать от типа интерфейса для конкретного типа.
Так вместо этого, я пошел по пути отражения:
public IFrobnicator<T> MakeFrobnicator<T>(T value)
{
if (value is IComparable<T>)
{
var constructor = typeof(ComparableFrobnicator<>).MakeGenericType(typeof(T)).GetConstructor(new[] { typeof(T) });
return (IFrobnicator<T>)constructor.Invoke(new object[] { value});
}
else if (value is IEquatable<T>)
{
var constructor = typeof(EquatableFrobnicator<>).MakeGenericType(typeof(T)).GetConstructor(new[] { typeof(T) });
return (IFrobnicator<T>)constructor.Invoke(new object[] { value });
}
else throw new ArgumentException();
}
Это, кажется, работает отлично, но выглядит как шаг назад в языке с такими умозаключениями мощного типа, как я привык. Есть что-то, чего я пропускаю, или лучшая техника, которую я пропустил?
В вашем комбинированном методе значение типа T в качестве параметра, то вы видите, является ли тип значения IComparable или IEquatable . Что-то там не так. –
David
@ Давид, например. 'int', является' IComparable '* и *' IEquatable '. Тип, представляющий комплексные числа, может быть приравнен к себе, но не сопоставим. –
RoadieRich
Кажется, что последний метод должен быть ограничен IComparable –