C#(99):泛型 System.Collections.Generic及泛型继承、运算符、结构、接口、方法、委托、事件、可空类型等

一、定义泛型类

void Main()
{
    //实例化泛型类时,才指定具体的类型
    MyGenericClass<int> MyGeneri = new MyGenericClass<int>(5);
    Console.WriteLine(MyGeneri.InnerT1Object * 2);
}

public class MyGenericClass<T>//<T1,T2,T3>表示多个类型参数
{
    private T innerT1Object;
    public string LastName;
public MyGenericClass(T item)//构造函数
    {
        this.innerT1Object = item;
    }
public T InnerT1Object//泛型属性
    {
        get { return innerT1Object; }
    }
}

注意:

1、不能假定T提供了什么类型。

eg:innerT1Object=new T(),因为T可能根本无公共默认构造函数。除非 class MyGenericClass<T> where T:new()

public class MyGenericClass<T> where T : new()
{
    private T innerT1Object = new T();
}

2、可以把T看作继承System.Object的类型:typeof(T),T.ToString()

3、在没有指定约束类型参数的情况下,比较泛型类型值和null,只能使用==或!=。

不能对两个类型值变量进行比较。

public bool Compare(T op1, T op2)
{
    if (op1 != null && op2 == null)//正确。如果T为值类型,op1!=null始终成立。
    {
        //
    }
    if (op1 == op2)//错误,因为这就假定了T支持==运算符
    {
        //
    }
}

4、default关键字用于为T赋默认值,而无需考虑其实值类型还是引用类型。

public class MyGenericClass<T>
{
    private T innerT1Object = default(T);
}

5、where 关键字用于约束T的类型。

class MyGenericClass<T> where T:Animal

可用的约束有:

  • struct :值类型
  • class:引用类型
  • <baseclass>:此列或者此类的派生类
  • <interface>:此接口或者实现此接口
  • new():必须具有无参数的公共构造函数。必须为类型的最后得约束。
  1. 一个类型参数可有多个约束:class Myclass<T> where T: constait1,constrait2
  2. 各类型参数不同的约束:class Myclass<T1,T2> where T1: constait1,T2:constrait2
  3. 约束放于继承符之后:class Myclass<T1>:MyBaseCalss,IMyInterface where T: constait
  4. 一个类型参数用作另一个类型参数的约束,表示T2与T1的类型相同,或T2继承于T1(裸类型约束)class Myclass<T1,T2> where T2: T1

6、泛型类的静态成员只能在类的一个实例中共享:

void Main()
{
    StaticDemo<string>.x=4;
    StaticDemo<int>.x=5;
}

public class StaticDemo<T>  
{
    public  static int x;
}

二、从泛型类继承

1、泛型类至少与基类有相同的约束,或为基类的子集

public class Farm<T> where T : Animal
{
    //...
}

public class SuperFarm<T> : Farm<T> where T : SuperCow //SuperCow为Animal的子集
{
    //...
}

2、类继承泛型,必须提供所有的类型信息

public class Cards : List<Card> //派生非泛型
{ }

三、定义泛型运算符

public static Farm<T> operator +(Farm<T> farm1, Farm<T> farm2)
{ }

四、定义泛型结构

public struct MyStruct<T1, T2>
{
    public T1 item1;
    public T2 item2;
}

五、定义泛型接口

interface myInterface<T> where T : Animal
{
    bool Brea(T animal1, T animal2);
    T oldest { get; }
}

实例:

public interface IComparable<T>
{
    int CompareTo(T other);
}

public class Person : IComparable<Person>
{
    public int CompareTo(Person other)
    {
        return this.name.CompareTO(other.name);
    }
}

六、定义泛型方法

1、普通类

public class Defaulter
{
    public T GetDefault<T>()
    {
        return default(T);
    }
}

2、泛型类

public class Defaulter<T1>
{
    public T2 GetDefault<T2>() where T2 : T1 //泛型方法的参数最好不要与其所在的泛型类的类型参数相同
    {
        return default(T2);
    }

    public void Process()
    {
    }
    public void Process<T>(T1 op1)//重载方法1
    {
    }

    public void Process<T, U>(T1 op1)//重载方法2
    {
    }
}

七、定义泛型委托

1、通过泛型委托,委托的参数可以在以后定义。

public delegate T1 MyDelegate<T1, T2>(T2 op1, T2 op2) where T1 : T2;

2、常用内置委托:

(1)、Action<T>: 泛型委托。无返回值。 委托的方法可以有1-16个输入参数。Action:无参数无返回值委托。

Action action1 = () => Console.Write("a");
action1();

Action<string> action2 = (p) => Console.Write(p);
action2("b");

利用Action实现线程和界面交互:

private void button1_Click(object sender, EventArgs e)
{
    WaitCallback waitCallBack = new WaitCallback(this.AlternationUsingAction);
    ThreadPool.QueueUserWorkItem(waitCallBack, "Action的使用");
}

private void AlternationUsingAction(object text)
{
    this.Invoke((Action)( () =>
      {
          button1.Text = text.ToString();
      } ));
}

(2)、Func<T>:必须具有返回值。委托的方法可以有0-16个参数输入参数,加一个输出参数。

Func<int, int, string > Func = (a, b) => (a + b).ToString();
Console.Write(Func(1, 2));

(3)、Predicate<T>:就是只接受一个传入参数,返回值为bool类型。

用于搜索方法

public delegate bool Predicate<T>(T obj);//判断条件函数
public T Find(Predicate<T> matach);

举例:

Predicate<string[]> predicate = x =>
                   {
                       var result = from p in x
                                    where p.Contains("s")
                                    select p;
                       return result.ToList().Count > 0;

                   };
string[] _value = { "charlies", "nancy", "alex", "jimmy", "selina" };
Console.WriteLine(predicate(_value) ? "包含." : "不包含");

(4)、Comparision<T>(T obj1,T obj2):比较函数,用于搜索方法。

public delegate int Comparision<T>(T obj1,T obj2)//
public void Sort(Comparision<T> comprison)

(5)、EventHandler<TEventArgs>:泛型事件处理函数。

public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs : EventArgs;

3、实例:

public delegate TSummary Action<TInput, TSummary>(TInput t, TSummary u);//定义泛型委托
public static TSummary Accumulate<TInput, TSummary>(IEnumerable <TInput> cols, Action<TInput, TSummary> action)
//将委托实例action传给方法参数。
{
    TSummary sum = default(TSummary);
    foreach (TInput input in cols)
    {
        sum = action(input, sum);//执行委托方法
    }
    return sum;
}

void Main()
{
    decimal amount = Accumulate<int, decimal>(new List<int> { 1, 2 }, (a, b) => a + b);//(a, b) => a + b为委托实例
    Console.Write(amount);
}

八、定义泛型事件

事件与委托就像一对孪生兄弟。既然有泛型委托,那么也应该有泛型事件。因为在以前,事件处理函数的发送方参数的类型总是Object。因此事件处理函数没有办法根据不同的发送者身份或者类型对事件进行不同的处理。现在如果使用泛型事件就可以使用强类型的发送方,不再需要强制转换成Object或反向强制转换。而且也可以根据发送方类型的不同对消息进行不同的处理。

例子中演示了发送方是强类型的情况,在这个例子中使用泛型类Publisher<T>来表示消息的发布者,用类Receiver来表示消息的订阅者。

//定义了一个泛型委托,该委托指定了发送者的具体类型
public delegate void MyEventHandler<T>(Publisher<T> Sender);

void Main()
{
    //事件发布者
    Publisher<int> publisherI = new Publisher<int>();
    Publisher<double> publisherD = new Publisher<double>();

    //事件订阅者
    Receiver receiver = new Receiver();

    //开始绑定事件
    publisherI.Click += receiver.OnClick;
    publisherD.Click += receiver.OnClick;

    //引发事件
    publisherI.SendMessage();
    publisherD.SendMessage();
}

//消息发布者类Publisher<T>的代码
public class Publisher<T>
{
    //定义了一个泛型事件,该事件的发布者的类型是强类型
    public event MyEventHandler<T> Click;

    //发送事件函数
    public void SendMessage()
    {
        Click(this);
    }
}

//消息订阅者类Receiver的代码
class Receiver
{
    //事件处理函数,该函数具有强类型的参数表示发送者
    public void OnClick(Publisher<int> sender)
    {
        Console.WriteLine("该事件已经写入日志文件");
    }

    //事件处理函数
    public void OnClick(Publisher<double> sender)
    {
        Console.WriteLine("该事件已经发送到主管信箱");
    }
}

九、可空类型System.Nullable<T>

1、声明和赋值

Nullable<int> x = 4;//可写成int? x = 4
x = null;//可为可空类型赋值null.

2、判断为空

int y;
if (x.HasValue)//或者x!=null
{
    y = x = value;
}
else
{
    y = x ?? 0;//或者    x.GetValueOrDefault(); x=null则或者其默认值。
}

3、转换

int? op1=5;
int? result=op1 *2;

int? op2=5;
int result1=op2 *2;//如果op2为null,强制转换int?到int产生异常

十、ArraySegement<T> 数组片段

int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8 };
ArraySegment<int> segment = new ArraySegment<int>(arr, 2, 3);
for (int i = segment.Offset; i < segment.Offset + segment.Count; i++)
{
    Console.WriteLine(segment.Array[i]);
}

posted on 2018-08-06 09:59  springsnow  阅读(240)  评论(0编辑  收藏  举报

导航