🚫 Ad Blocker Detected

Please disable your AD blocker to continue using this site. Ads help us keep the content free! please press keyboard F5 to refresh page after disabled AD blocker

請關閉廣告攔截器以繼續使用本網站。廣告有助於我們保證內容免費。謝謝! 關閉後請按 F5 刷新頁面

0%

(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 一般泛型預設就是這個

泛型中的共變數和反變數

out (generic modifier) (C# Reference)

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

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