in (универсальный модификатор) (Справочник по C#)
Для параметров универсального типа ключевое слово in
указывает, что параметр типа является контравариантным. Ключевое слово in
может применяться в универсальных интерфейсах и делегатах.
Контравариантность позволяет использовать производные типы со степенью наследования меньше, чем у типа, заданного универсальным параметром. Благодаря этому можно осуществлять неявное преобразование классов, реализующих контравариантные интерфейсы, и неявное преобразование типов делегатов. Ковариантность и контравариантность поддерживаются для ссылочных типов, но не для типов значений.
Тип может быть объявлен контравариантным в универсальном интерфейсе или делегате, только если он определяет тип параметров метода, но не тип значения, возвращаемого методом. In
, ref
и out
параметры должны быть инвариантными, то есть они не являются ковариантными и контравариантными.
Интерфейс с параметром контравариантного типа позволяет своим методам принимать аргументы производных типов, степень наследования у которых меньше, чем у параметра типа интерфейса. Например, в интерфейсе IComparer<T> тип T является контравариантным, поэтому можно присвоить объект типа IComparer<Person>
объекту типа IComparer<Employee>
без применения каких-либо специальных методов преобразования, если Employee
наследует Person
.
Контравариантный делегат может быть назначен другому делегату того же типа, но с производным параметром универсального типа меньшей степени.
Дополнительные сведения см. в разделе Ковариация и контравариантность.
Контравариантный универсальный интерфейс
В следующем примере показано, как объявить, расширить и реализовать контравариантный универсальный интерфейс. В нем также показано, как можно использовать неявное преобразование для классов, реализующих этот интерфейс.
// Contravariant interface.
interface IContravariant<in A> { }
// Extending contravariant interface.
interface IExtContravariant<in A> : IContravariant<A> { }
// Implementing contravariant interface.
class Sample<A> : IContravariant<A> { }
class Program
{
static void Test()
{
IContravariant<Object> iobj = new Sample<Object>();
IContravariant<String> istr = new Sample<String>();
// You can assign iobj to istr because
// the IContravariant interface is contravariant.
istr = iobj;
}
}
Контравариантный универсальный делегат
В следующем примере кода показано, как объявить контравариантный универсальный делегат. В нем также показано, как можно выполнить неявное преобразование типа делегата.
// Contravariant delegate.
public delegate void DContravariant<in A>(A argument);
// Methods that match the delegate signature.
public static void SampleControl(Control control)
{ }
public static void SampleButton(Button button)
{ }
public void Test()
{
// Instantiating the delegates with the methods.
DContravariant<Control> dControl = SampleControl;
DContravariant<Button> dButton = SampleButton;
// You can assign dControl to dButton
// because the DContravariant delegate is contravariant.
dButton = dControl;
// Invoke the delegate.
dButton(new Button());
}
Спецификация языка C#
Дополнительные сведения см. в спецификации языка C#. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.