Effective C# 22.支援泛型的共變數與反變數 Effective C# 22.支援泛型的共變數與反變數 (Support Generic Covariance and Contravariance)

Published on Friday, October 18, 2024

這個做法提出了三個概念: 共變數(Covariance)、反變數(Contravariance)與不變數(Invariant)。

直接閱讀程式碼比較容易理解,從英文來看比較容易理解 less derived type 代表繼承中較低位階的類型, 我們知道在 C# 中所有類型都是從 Object 衍生出來的,所以在這個例子中 Object 跟其它類型比起來就是一個 less derived typemore derived type 則是高位階類型例如 string 類型就是從 Object 衍生出來的。 這個就是類型間相容性的概念。

void Main()
{
	// Assignment compatibility.
	string str = "test";
	// An object of a more derived type is assigned to an object of a less derived type.
	object obj = str;
}

但是下面這種寫法看似正確但結果是會編譯錯誤,這是因為泛型類型沒有特別指定的話都是 Invariant,代表傳遞給該參數的變數型別必須跟宣告的型別完全一樣。

void Main()
{
	List<string> strings = new List<string>();
	List<object> objects = strings;
}

所以在新版的 C# 引入了 Covariance 的概念,例如下面這段程式碼的寫法可以把 List<string> 賦值給 IEnumerable<string>型別, 也就是把高位階的類型賦值給低位階的類型。

void Main()
{
	// Covariance.
	IEnumerable<string> strings = new List<string>();
	// An object that is instantiated with a more derived type argument
	// is assigned to an object instantiated with a less derived type argument.
	// Assignment compatibility is preserved.
	IEnumerable<object> objects = strings;
}

能做到這樣的效果都是靠新的參數 inout,所以上面用到的 IEnumerable 內部就是加上了 out 參數進行修飾,才能獲得 Covariance 的功能。

public interface IEnumerable<out T> : IEnumerable

Contravariance 則是相反的概念,像下面這段程式碼就是把 Action<object> 賦值給 Action<string>,也就是低位階的類型賦值給高位階的類型。

public class Contravariance
{
	// Contravariance.
	// Assume that the following method is in the class:
	static void SetObject(object o) { }
	
	public void Create()
	{
		Action<object> actObject = SetObject;
		// An object that is instantiated with a less derived type argument
		// is assigned to an object instantiated with a more derived type argument.
		// Assignment compatibility is reversed.
		Action<string> actString = actObject;
	}
}

上面用到的 Action 內部就是加上了 in 參數進行修飾,才能獲得 Contravariance 的功能。

public delegate void Action<in T>(T obj);

Summary

這個做法提到了泛型會被視為 Invariant,所以現在建議是加上 inout 來修飾介面和委派讓我們的類型獲得 Covariance 與 Contravariance 的功能。