C#基础系列—泛型(Generics)(下)

 
C#基础系列—泛型(Generics)(下)
 
(转载请注明--Huwz)
我们已经知道,泛型包括了类、结构、接口、方法和委托。除此之外,泛型还可以使用约束(Constain)。使用泛型约束自然有其意义,且看下文说来。
通过C#基础系列—泛型(Generics)(上)的介绍,我相信大家应该很容易写出普通的泛型了。因此在这里我就不详细介绍了。对泛型的类、结构、接口、方法和委托我各写出一个例子。
public class MyClasskkk<T>
    {
        T member = default(T);
    }
 
泛型类
 
应用泛型的字段
 
 
public struct MyStruct<T>
    {
        T member;
    }
 
泛型结构
 
应用泛型的字段
 
 
public interface IMyInterface<T>
    {
        void MyMethod<M>(M obj);
    }
 
泛型接口
 
泛型方法(不一定使用接口提供的泛型)
 
 
public delegate T MyHandle<T>(T obj);
泛型委托
 
 
l 值类型/引用类型约束
l 基类约束
l 接口约束
l 构造约束
说起约束,总给我一种不自在的感觉——我为什么非要让我的类型是从某个类型或接口继承下来呢?这样不是限制了我使用的类型了吗,“泛”型都不泛了,还有什么意义?
其实,约束从使用的感觉上来说,确实是牺牲了一些自由度,但是却换回了更有意义的可操作性。
 
看看下面的代码
   public abstract class MyBaseClass
    {
        public abstract void MethodFoo();
        public abstract void MethodBar();
}
 
    public class MyGenericClass<T> where T:MyBaseClass
    {
        //...
 }
 
我们的泛型类MyGenericClass的T被约束成MyBaseClass类型,除了MyBaseClassMyBaseClass继承类之外,T不能使用其它任何类型了。这就是泛型的约束。
但是我们也能获得约束带来的好处。我们知道,在C#中,所有的类型都是从Object继承下来的,没有使用约束的泛型,可以等价为约束为Object的泛型。
因此这些类型只能提供Object里的一些方法,比如ToString(),GetHashCode(),Equal(),GetType()。但是当我们需要实现某些其他操作的时候,这些泛型的对象就无能为力了。
但是如果我们使用的是带约束的泛型,我们就可以拥有约束类型中的方法。比如:
    public class MyGenericClass<T> where T:MyBaseClass
    {
        public MyGenericClass()
        {
            T obj = default(T);
            obj.MethodBar();
            obj.MethodFoo();
        }
    }
 
Ok ,让我们看看怎么这四种约束类型都有什么样的特点吧
约束
示例
说明
值类型/ 引用类型约束
class MyClass<T> where T: class
T 类型必须是引用类型
class MyClass<T> where T: struct
T 类型必须是值类型
基类约束
class MyClass<T> where T: MyBaseClass
T 类型必须是MyBaseClass或从MyBaseClass继承下来
接口约束
class MyClass<T> where T: IMyInterface
T 类型必须是应用了IMyInterface接口的类型
构造约束
class MyClass<T> where T: new()
T 类型必须包含一个不带参数的构造函数
 
补充一点,在构造约束里,似乎只有这一种类型;没有任何带参的构造约束。
在泛型这些约束里,估计比较常见的是IComparable接口约束。因为应用泛型最多的是集合,当涉及到给集合里的元素排序的时候,应用IComparable接口就比较合理了。
 
如果有多个约束的情况下,那就这么写就可以了
class MyClass<T,U>
where T: new()
where U: class
{
//
}
泛型的继承
继承很简单,不过要看清楚:
假如有这么两个类: BaseClass 和 DerivedClass,且DerivedClass继承自BaseClass。还有一个泛型类MyClass<T>。那么假如我这么写——
MyClass<BaseClass> obj = new MyClass<DerivedClass>();
有没有问题?
 
使用基类表示继承类的对象,会有问题吗?这话说的没错,但此处却不适用。
这行代码的等号左右,实际上是表示两个完全不同的类。因此编译时肯定出错。看仔细了,这并不是泛型的继承。
 
其实,泛型类的继承和普通的类继承很相似
public class MyClass<T> : MyBaseClass<T>
    {
}
类型要保留下来。基类提供的泛型类型不能超过子类的泛型类型。
也就是说,可以使泛型类继承自非泛型类
public class MyClass2<T> : MyBaseClass2
    {
}
但是不允许非泛型类继承自泛型类
public class MyABC : MyClass2<T>
    {
}
 
其它的情况在理解上可以同理一下。比如说
public class MyClass<T> : MyBaseClass<T,U>
    {
}
这个不行,因为多了个U,所以就可以同理非泛型继承泛型。
public class MyABC<T> : MyClass2<int>
    {
}
这个可以,因为指定了泛型的类型,所以相当于固定类型。
public class MyBaseClass2<U,T>: MyBaseClass<T,U>
    {
}
这个当然也没有问题。从来都没有说泛型还有顺序的规定。
 
其它
有时候泛型方法和普通方法可能会产生误会,比如下面这个小测验。虽然一般来讲不推荐把代码写成这样,但有时候难免会碰到这样的麻烦。所以我要再此补充一个“硬道理”——是泛型用泛型,有非泛型可用就用非泛型。下面这个小测验,大家可以尝试一下 J
class Program
    {
        static void Main(string[] args)
        {
            A<int> a = new A<int>();
            a.Test(12);
            a.InternalTest(12);
        }
    }
 
    class A<T>
    {
        public void InternalTest(T obj)
        {
            Test(obj);
        }
 
        public void Test(T obj)
        {
            Console.WriteLine("T");
        }
 
        public void Test(int obj)
        {
            Console.WriteLine("int");
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值