(C#)委託delegate,Func<>,Action 解說系列(三)

前文:

在Func和Action泛型委託中 有 In , Out 兩個關鍵字

那到底是神麼意思呢?

讓我們一起看下去….

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

//fun delegate
public delegate TResult Func<in T, out TResult>(T arg);

上面程式碼我列出ActionFunc 委派方法各其中一個重載

我們可以發現到泛型中有關鍵字 inout 這是代表神麼意思呢?

讓我們繼續看下去…..

解說:

分享前先探討一個問題 泛型是否可以父類別指向子類別

public interface IGeneric<T> { }
public class Base<T> : IGeneric<T> { }

public class A { }

class Program
{

    static void Main(string[] args)
    {
        IGeneric<object> b = new Base<object>();
        IGeneric<A> a = new Base<A>();
        //無法執行父類只向子類別 因為泛型預設是Invariance
        b = a;
        Console.ReadKey();
    }
}

上面範例程式很清楚知道無法編譯,那我要怎麼處理和解決的?

第一種解法 使用 AS :

public interface IGeneric<T> { }
public class Base<T> : IGeneric<T> { }

public class A { }

class Program
{

    static void Main(string[] args)
    {
        IGeneric<object> b = new Base<object>();
        IGeneric<A> a = new Base<A>();
        //使用AS來轉型
        b = a as IGeneric<object>;
        Console.ReadKey();
    }
}

第二種解法 在interface的泛型中使用 Out (今天要介紹的主角)

//這裡使用out將T 解釋為Covariance
public interface IGeneric<out T> { }
public class Base<T> : IGeneric<T> { }

public class A { }

class Program
{

    static void Main(string[] args)
    {
        IGeneric<object> b = new Base<object>();
        IGeneric<A> a = new Base<A>();
        //在上面的泛型用out
        b = a;
        Console.ReadKey();
    }
}

三個重要名詞 Covariance,Contravariance,Invariance

MSDN中有解釋 此關鍵字 泛型中的共變數和反變數

Covariance(共變數) :

MSDN說明:可讓您使用比原本指定更多衍生的類型。您可以將 IEnumerable (在 Visual Basic 中為 IEnumerable(Of Derived)) 的執行個體指派給 IEnumerable 類型的變數
簡單說明:泛型支援父類指向子類別 [泛型中使用out ] (支援泛型介面或泛型委派)
如下面的範例:

IGeneric<out T>所以下面a付值給b就不需轉型

//這裡使用out將T 解釋為Covariance
public interface IGeneric<out T> { }
public class Base<T> : IGeneric<T> { }

public class A { }

class Program
{

    static void Main(string[] args)
    {
        IGeneric<object> b = new Base<object>();
        IGeneric<A> a = new Base<A>();
        //在上面的泛型用out
        b = a;
        Console.ReadKey();
    }
}

Contravariance(反變數)

MSDN說明:可讓您使用比原本所指定更泛型 (較少衍生) 的類型。您可以將 IEnumerable (在 Visual Basic 中為 IEnumerable(Of Base)) 的執行個體指派給IEnumerable 類型的變數。

簡單說明:可將父類物件引用賦予給子類別 [泛型中有in]
如下範例:

IComparer<in T> 所以子類可以取得父類的引用

//這裡使用in將T 解釋為Contravariance
public interface IGeneric<in T> { }

public class Base<T> : IGeneric<T> { }

public abstract class Shape
{
    public virtual double Area { get { return 0; } }
}

public class Square : Shape
{
    private double r;
    public Square(double radius) { r = radius; }
    public double Radius { get { return r; } }
    public override double Area { get { return r * r; } }
}

public class Circle : Shape
{
    private double r;
    public Circle(double radius) { r = radius; }
    public double Radius { get { return r; } }
    public override double Area { get { return Math.PI * r * r; } }
}

public class ShapeAreaComparer : IComparer<Shape>
{
    int IComparer<Shape>.Compare(Shape a, Shape b)
    {
        if (a == null) return b == null ? 0 : -1;
        return b == null ? 1 : a.Area.CompareTo(b.Area);
    }
}

class Program
{

    static void Main(string[] args)
    {
        //泛型[形狀類別(基類)]
        IGeneric<Shape> b = new Base<Shape>();
        //泛型[圓形類別(子類)]
        IGeneric<Circle> a = new Base<Circle>();
        //子類可以取得父類引用
        a = b;
        Console.ReadKey();
    }
}

Invariance 只能該類別指向該類別
一般泛型預設就是這個


總結:

Func 泛型委派的最後一個泛型類型參數會指定委派簽章中的傳回值類型

Covariance (共變數) (out 關鍵字) 泛型支援父類指向子類別

Contravariant (反變數) (in 關鍵字) 泛型子類可以取得父類的引用

Invariance 一般泛型預設就是這個

泛型中的共變數和反變數.aspx)

out (generic modifier) (C# Reference)

此文作者:Daniel Shih(石頭)
此文地址https://isdaniel.github.io/c-func-3/
版權聲明:本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 TW 許可協議。轉載請註明出處!


如果本文對您幫助很大,可街口支付斗內鼓勵石頭^^