반응형
Covariance and Contravariance (C#)
용어 정리
Invariance | Means that you can use only the type originally specified. An invariant generic type parameter is neither covariant nor contravariant. You cannot assign an instance of List to a variable of type List or vice versa. |
|
Variance | Convariance | Enables you to use a more derived type than originally specified. You can assign an instance of IEnumerable to a variable of type IEnumerable. |
Contravariance | Enables you to use a more generic (less derived) type than originally specified. You can assign an instance of Action to a variable of type Action. |
in (Generic Modifier) (C# Reference)
Contravariance enables
- IContravariance<ClassB> 의 SetValue 에서 GetA 와 GetB 를 사용할 수 있다.
- IContravariance<ClassB> 를 IContravariance<ClassC> 로 conversion 후 SetValue 에서 GetA 와 GetB 를 사용할 수 있다.
- IContravariance<ClassB> 를 IContravariance<ClassA> 로 conversion 후 SetValue 에서 GetA 는 사용할 수 있지만, GetB 를 사용하는 것은 문제가 될 수 있다.
- 따라서 IContravariance<ClassB> 를 IContravariance<ClaassA> 로 conversion 하는 것은 허용하지 않는다.
class ClassA
{
public void GetA() { }
}
class ClassB : ClassA
{
public void GetB() { }
}
class ClassC : ClassB
{
public void GetC() { }
}
interface IContravariance<in T>
{
// T GetValue(); // CS1961: 잘못된 가변성(variance): 'T' 형식 매개 변수는 'IContravariance<T>.GetValue()' 에서 유효한 공변(covariant) 방식이어야 합니다. 'T'(은)는 반공변(contravariant)입니다.
void SetValue(T t);
}
class CreateB : IContravariance<ClassB>
{
public void SetValue(ClassB t) { }
}
public void Run()
{
IContravariance<ClassB> creatorB = new CreateB();
IContravariance<ClassC> creatorC = creatorB;
// IContravariance<ClassA> creatorA = creatorB;
}
out (generic modifier) (C# Reference)
Covariance enables
- ICovariance<ClassB> 의 GetValue 값에서 GetA 와 GetB 를 사용할 수 있다.
- ICovariance<ClassB> 를 ICovariance<ClassA> 로 conversion 후 GetValue 값에서 GetA 를 사용할 수 있다.
- ICovariance<ClassB> 를 ICovariance<ClassC> 로 conversion후 GetValue 값에서 GetA 와 GetB 는 사용할 수 있지만, GetC 를 사용하는 것은 문제가 될 수 있다.
- 따라서 ICovariance<ClassB> 를 ICovariance<ClassC> 로 conversion 하는 것은 허용하지 않는다.
class ClassA
{
public void GetA() { }
}
class ClassB : ClassA
{
public void GetB() { }
}
class ClassC : ClassB
{
public void GetC() { }
}
interface ICovariance<out T>
{
T GetValue();
// void SetValue(T t); // CS1961:잘못된 가변성(variance): 'T' 형식 매개 변수는 'ICovariance<T>.SetValue(T)'에서 유효한 반공변(contravariant) 방식이어야 합니다. 'T'은(는) 공변(covariant)입니다.
}
class CreateB : ICovariance<ClassB>
{
public ClassB GetValue() { return new ClassB(); }
}
public void Run()
{
ICovariance<ClassB> creatorB = new CreateB();
ICovariance<ClassA> creatorA = creatorB;
// ICovariance<ClassC> creatorC = creatorB;
}
Variance in Generic Interfaces (C#)
Starting with .NET Framework 4, the following interfaces are variant:
IEnumerable<T> (T is covariant)
Why was IEnumerable made covariant in C# 4?
namespace System.Collections.Generic
{
public interface IEnumerable<out T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
}
IEnumerator<T> (T is covariant)
namespace System.Collections.Generic
{
public interface IEnumerator<out T> : IEnumerator, IDisposable
{
T Current { get; }
}
}
IQueryable<T> (T is covariant)
using System.Collections;
using System.Collections.Generic;
namespace System.Linq
{
public interface IQueryable<out T> : IEnumerable<T>, IEnumerable, IQueryable
{
}
}
IGrouping<TKey,TElement> (TKey and TElement are covariant)
using System.Collections;
using System.Collections.Generic;
namespace System.Linq
{
public interface IGrouping<out TKey, out TElement> : IEnumerable<TElement>, IEnumerable
{
TKey Key { get; }
}
}
IComparer<T> (T is contravariant)
namespace System.Collections.Generic
{
public interface IComparer<in T>
{
int Compare(T x, T y);
}
}
IEqualityComparer<T> (T is contravariant)
namespace System.Collections.Generic
{
public interface IEqualityComparer<in T>
{
bool Equals(T x, T y);
int GetHashCode(T obj);
}
}
IComparable<T> (T is contravariant)
namespace System
{
public interface IComparable<in T>
{
int CompareTo(T other);
}
}
Starting with .NET Framework 4.5, the following interfaces are variant:
IReadOnlyList<T> (T is covariant)
namespace System.Collections.Generic
{
[DefaultMember("Item")]
public interface IReadOnlyList<out T> : IEnumerable<T>, IEnumerable, IReadOnlyCollection<T>
{
T this[int index] { get; }
}
}
IReadOnlyCollection<T> (T is covariant)
namespace System.Collections.Generic
{
public interface IReadOnlyCollection<out T> : IEnumerable<T>, IEnumerable
{
int Count { get; }
}
}
반응형
'Works > C#' 카테고리의 다른 글
C# 암호화 변수 (0) | 2020.09.23 |
---|---|
[.NET] Windows Registry 등록/삭제 (0) | 2019.09.08 |
[.NET] Java Bridge (2) | 2019.03.22 |
For vs Foreach (0) | 2018.12.04 |
댓글