泛型的学习笔记,开端聊聊C

时间:2019-09-21 00:57来源: 操作系统
小编们在一般的支出职务中,平常碰着对分裂的数据结构施行同样的操作,比方有叁个措施传入的参数恐怕是字符串也只怕是数字,那样的情景下,一般大家是一直传入一个object类型的

小编们在一般的支出职务中,平常碰着对分裂的数据结构施行同样的操作,比方有叁个措施传入的参数恐怕是字符串也只怕是数字,那样的情景下,一般大家是一直传入一个object类型的参数,以便于能够兑现那样的效果与利益。比方以下代码。

在JAVA中,泛型只被JAVA编写翻译器帮衬,并不被JVM所支撑,约等于说未有定义新的字节码来代表泛型类型,自然在JVM里面也不会有新的授命来帮衬新的字节码。类比到.NET来讲,也便是被C#编译器援救而不被CL凯雷德所支撑。那样就发出了十分的多风趣的主题材料。我们都明白大家的代码都要由此编写翻译器的翻译改造,JAVA中的泛型就是JAVA编写翻译器采纳类型擦除的法子来完结泛型的。定义的泛型类型,都活动提供了二个应和的原始类型(raw type)原始类型的名字就是剔除类型参数后的泛型名,擦出掉类型变量,并替换为限制品种(Infiniti定的变量用Object),能够看做是语法糖啊。举个例子:

private static void Show

view sourceprint?public class MyHashMap<TKey, TValue> { 

{

    private HashMap<TKey, TValue> m_map = new HashMap<TKey, TValue>(); 

Console.WriteLine(a.ToString;

      

}

    public TValue get(TKey key) { 

如此那般的代码可是落实大家须求的法力,不过规定也很显明:1、只是传入贰个object类型的参数,对于调用方来讲,根本不晓得应该传入四个怎么样类型的参数,很有希望认为参入参数的标题变成代码运维战败。2.object是一个援引类型,假诺我们要管理的是二个值类型,那么就能够时有爆发装箱和拆箱的操作,频繁的装箱拆箱会对前后相继的习性产生特大的震慑。在如此的供给下,C#2.0引进了泛型的概念,用于提供通用的效应以及编译时的种类安全。

        return this.m_map.get(key); 

一、泛型的定义

    } 

泛型的定义特别轻松,<T>就能够<>尖括号不可能差不离,T代表须要操作的切切实实品种,T不是一向的你能够运用另外有含义的号子替代。比方以下定义

      

private static void Show<TValue>

    public void put(TKey key, TValue value) { 

{

        this.m_map.put(key, value); 

Console.WriteLine(a.ToString;//电视机alue代表必要操作的门类,供给小心的是TValue是种类并非实例

    } 

}

  

泛型的定义能够献身方法方面,也足以放在整个类地方,放在方法方面那么独有当前艺术是泛型方法,而平素放在类地方,则是把全副类全部概念为了泛型类,类内部的其余方法再利用此泛型的时候都得以绝不再定义,就算要求定义两个泛型参数,则使用逗号隔绝全数的参数,举例

    public static void main(String[] args) { 

private static void Show<TKey,TValue>

        MyHashMap<String, Integer> map = new MyHashMap<String, Integer>(); 

{

        map.put("Hello", 5); 

Console.WriteLine(a.ToString;

        int i = map.get("Hello"); 

}

    }     

二、泛型方法的利用

}

概念了泛型方法将在去行使它,要是定义了如下的泛型方法

 

private static TValue Show<TValue>

编写翻译成字节码后,就成了上边那些样子(这里还用JAVA代码来表示)

{

public class MyHashMap {    private HashMap m_map = new HashMap();        public Object get(Object key) {        return this.m_map.get(key);    }        public void put(Object key, Object value) {        this.m_map.put(key, value);    }    public static void main(String[] args) {        MyHashMap map = new MyHashMap();        map.put("Hello", 5);        int i = (Integer)map.get("Hello");    }    }好呢,看到Object,小编显著本身又想起装箱了,可以见见Java中的泛型没有缓慢解决装箱难点。

Console.WriteLine(a.ToString;

是因为JVM并不知道泛型类型,所以JAVA中正是以JAVA编写翻译器的语法糖的样式来显现的。当初作者刚接触JAVA的时候,的确会被上面两种错误弄得很疑心。

return a;

view sourceprint?public class MyClass<SomeType> { 

}

    public static void myMethod(Object item) { 

那正是说相应怎么调用他呢?

        if (item instanceof SomeType) { // 报错 

Show<string>;

            ... 

Show<int>;

        } 

在<>中使用须要操作的品种取代电视机alue这几个标志

        SomeType st = new SomeType(); // 报错 

图片 1

        SomeType[] myArray = new SomeType[10]; // 报错 

地点正是调用泛型方法的结果。

    } 

三、泛型约束

}

神蹟我们供给大家的泛型参数知足一定的尺码,比如我们须求T承接自IComparable接口,大概大家渴求T不能是值类型,只好是引用类型这样的须要,该怎样满意呢?很简短,使用where就可以,例如以下定义

 

//以下定义要求电视机alue必得是三个援用类型

 

private static TValue Show<TValue> where TValue:class

在此处我们能够想转手,到底怎么着才算真正的支撑泛型呢?在.NET中,末了是由CL福睿斯根据元数据来试行IL代码,因而,能够很轻易明白:

{

1.IL中必将会有一个新命令来分辨“类型参数”。

Console.WriteLine(a.ToString;

2.大家了解类型和章程的定义在元数据表中都会有相应的表示,由此为了支持泛型,元数据的格式也会具备改观。

return a;

3.修改JIT编译器来进行新的IL指令。

}

也正是说,泛型类型定义能够完整的编写翻译为MSIL类型。

有了那样的定义,假诺大家在调用泛型方法的时候把电视alue定义为了三个值类型,那么VS的智能提示就能够在编写翻译时报错,那样就提供了编写翻译时的等级次序安全。举个例子

 

设倘使供给TValue要满足四个供给的话,则应用逗号分开就能够

泛型类型的运作大致的流水线如下:

private static TValue Show<TValue> where TValue:class,IComparable,new ()

C#编写翻译器生成IL和元数据,表示泛型类定义,JIT编写翻译器则会把泛型类型定义与一层层的品类参数组合起来。

{

具体点来说,IL为初阶化有个别泛型类型的实例预留了占位符,JIT编写翻译器会在运营的时候,生成机器代码的时候“补全定义”。JIT把相应的IL代码编译成X86命令,同期优化。优化什么内容了呢?举个例子,在品种参数是援引类型的时候,就能够使用同一的机械代码来代表。为何是引用类型并不是值类型呢?因为引用类型基本上都以指针,本质上来说结构都以同一的。

Console.WriteLine(a.ToString;

此处又要谈一下类加载。JIT不是在有些类加载时就为其生成完整的X86指令,而是仅在类中的每种方法被第二回调用的时候才最早编写翻译的。(小编前日感到应该先讲讲项目,对象,线程栈和托管堆在运作时的互相关系相比较好)。那样,就能够先在IL代码上实行二个占位符替换步骤,替换来具体项目,随后再像普通类一样按需编写翻译。

return a;

好吧,你可以见见,在施行此前占位符被替换来具体品种了,由此泛型的相称度是一定高的。应该说就是规范相称。那么些会耳熏目染如啥地点方呢?在点子重载的时候就能够有显示了。对于二个派生于MyBase的目的的话,WriteMEsaage<T>(T obj)要比WriteMEsaage(MyBase obj)在重载相称上更优先。因为经过将T替换到MyDerived编写翻译器就足以成功一回“准确相称”,而WriteMEsaage(MyBase obj)则还亟需贰回隐式调换。于是泛型方法更有优势,除非在调用时举行显式类型转变。上面用代码表达:

}

view sourceprint?public class MyBase 

下边是常用的有的羁绊法规

  

  1. 务求必需是援用类型,where T:class
  2. 渴求必需是值类型,where T:struct
  3. 自律中能够有八个接口,但只可以有一个基类,因为品种承继须求单基类继承
  4. new ()要求T必得有二个无参构造函数,相同的时候new()必需放在约束的末尾,同一时间C#不扶助自律带参数的构造函数

别的更为详实的平整请参照他事他说加以考察MSDN

  

四、C#中常见的泛型

泛型能够用在点子,类型,接口,委托等等对象方面,在C#中有相当的多早已定义好的泛型供大家一贯动用,举个例子List<T>,Dictionary<TKey,TValue>,Func<T1,T2>,Action<T>等等。他们的应用方式,请参见MSDN或许电动百度,多谢!

  

   

  

public class MyDerived : MyBase 

  

  

    #region IMessageWriter Members 

  

    void IMessageWriter.WriteMessage() 

  

    { 

  

        Console.WriteLine("Inside MyDerived.WriteMessage"); 

  

    } 

  

    #endregion 

  

  

   

  

class Program 

  

  

    static void WriteMessage(MyBase b)    { 

  

        Console.WriteLine("Inside WriteMessage(MyBase)"); 

  

    } 

  

    static void WriteMessage<T>(T obj) 

  

    { 

  

        Console.Write("Inside WriteMessage<T>(T):  "); 

  

        Console.WriteLine(obj.ToString()); 

  

    } 

  

    static void Main(string[] args) 

  

    { 

  

        MyDerived d = new MyDerived(); 

  

        Console.WriteLine("Calling Program.WriteMessage"); 

  

        WriteMessage(d); //让编写翻译器猜想使用哪个相配方法 

  

        Console.WriteLine(); 

  

        Console.WriteLine("Cast to base object"); 

  

        WriteMessage((MyBase)d); 

  

        Console.WriteLine(); 

  

    } 

  

}

 

因此当你想协助某一类及其具备派生类时,基于基类创建泛型并非最佳的挑选。同样的,基于接口也是这么。

那便是说小编想针对,那时就必要通过运营时来决断了,当然,那并非最佳的解决方案,就算对调用者屏蔽了切实的完成,但还要会带运转时检查的开拓。

view sourceprint?Static void WriteMessage<T>(T obj){ 

  

         If(obje is MyBase){ 

  

                  WriteMessage(obj as MyBase);  //显式类型调换 

  

         }else { 

  

                  Conslole.Write(“Invoke WriteMessage<T>”) 

  

         } 

  

}

...

编辑: 操作系统 本文来源:泛型的学习笔记,开端聊聊C

关键词:

  • 上一篇:没有了
  • 下一篇:没有了