程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C# 關於變體

C# 關於變體

編輯:C#入門知識

關於協變和逆變
協變和逆變統稱為變體,這是用於數組類型,委托類型,泛型參數類型間進行隱式引用轉換用的語法規則,有點類似多態。


泛型接口中的變體
<1>協變

接口中聲明的方法的泛型返回類型,它可以接受派程度更大的返回類型

interface ICovariant
{
    R GetSomething();
    // The following statement generates a compiler error.
    // void SetSometing(R sampleArg);
}

<2>逆變
接口中聲明的方法的泛型參數類型,它可以接受派生程度更小的參數類型
interface IContravariant
{
    void SetSomething(A sampleArg);
    void DoSomething() where T : A;
    // The following statement generates a compiler error.
    // A GetSomething();            
}

<3> 協變和抗變的同時實現


interface IVariant
{
    R GetSomething();
    void SetSomething(A sampleArg);
    R GetSetSometings(A sampleArg);
}

<4>關於變體的一些理解
變體包括抗變,協變,它是為了處理泛型,委托中基類與派生類賦值問題而出現的,因此類似於多態。
關於協變我們很容易理解,它是實現派生級別高賦給派生級別低的。在泛型接口中,協變的標示是out,並且它表示的也是函數的返


回值,就根據這一點說明它就很類似。
關於抗變,接口中標示的是in,並且它表示的是傳入的函數參數,所以抗變中表象是派生級別低的賦給派生級別高的,實質上還是把


用派生級別高的來做輸入,輸入到派生級別低的函數參數中。


關於抗變的例子:
namespace ConsoleApplication24
{
    // Simple hierarchy of classes.
    public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }


    public class Employee : Person { }


    // The custom comparer for the Person type
    // with standard implementations of Equals()
    // and GetHashCode() methods.
    class PersonComparer : IEqualityComparer
    {
        public bool Equals(Person x, Person y)
        {
            if (Object.ReferenceEquals(x, y)) return true;
            if (Object.ReferenceEquals(x, null) ||
                Object.ReferenceEquals(y, null))
                return false;
            return x.FirstName == y.FirstName && x.LastName == y.LastName;
        }
        public int GetHashCode(Person person)
        {
            if (Object.ReferenceEquals(person, null)) return 0;
            int hashFirstName = person.FirstName == null
                ? 0 : person.FirstName.GetHashCode();
            int hashLastName = person.LastName.GetHashCode();
            return hashFirstName ^ hashLastName;
        }
    }


    class Program
    {


        public static void Test()
        {
            List employees = new List {
               new Employee() {FirstName = "Michael", LastName = "Alexander"},
               new Employee() {FirstName = "Jeff", LastName = "Price"}
            };


            // You can pass PersonComparer, 
            // which implements IEqualityComparer,
            // although the method expects IEqualityComparer.


            IEnumerable noduplicates =
                employees.Distinct(new PersonComparer());


            foreach (var employee in noduplicates)
                Console.WriteLine(employee.FirstName + " " + employee.LastName);
        }


        public static void Main()
        {
            Test();
        }
    }


}


泛型類型參數中的變體
<1>
如果要啟用隱式轉換,必須使用in或者out關鍵字
public delegate T SampleGenericDelegate ();

public static void Test()
{
    SampleGenericDelegate  dString = () => " ";


    // You can assign delegates to each other,
    // because the type T is declared covariant.
    SampleGenericDelegate  dObject = dString;           
}

<2>
如果您僅使用變體支持來匹配方法簽名和委托類型,且不使用 in 和 out 關鍵字,則可能會發現,有時可以用相同的 lambda 表達式或方法來實例化多個委托,但無法將一個委托指派給另一個委托。
public static void Test()
{
    SampleGenericDelegate dString = () => " ";
    SampleGenericDelegate dObject = () => " ";
    // SampleGenericDelegate  dObject = dString;	//error
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved