c#泛型_c#泛型转换 - CSDN
c#泛型 订阅
C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。C语言能以简易的方式编译、处理低级存储器。C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。尽管C语言提供了许多低级处理的功能,但仍然保持着跨平台的特性,以一个标准规格写出的C语言程序可在包括类似嵌入式处理器以及超级计算机等作业平台的许多计算机平台上进行编译。 [1] 展开全文
C语言是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。C语言能以简易的方式编译、处理低级存储器。C语言是仅产生少量的机器语言以及不需要任何运行环境支持便能运行的高效率程序设计语言。尽管C语言提供了许多低级处理的功能,但仍然保持着跨平台的特性,以一个标准规格写出的C语言程序可在包括类似嵌入式处理器以及超级计算机等作业平台的许多计算机平台上进行编译。 [1]
信息
类    别
程序设计语言
影响语言
C++、C#、D、Java、JavaScript、ObjectPHP等
创始时间
1972年
主要编译器
Visual C++、Clang、GCC、Turbo C等
中文名
C语言
创始人
Dennis MacAlistair Ritchie
发    源
BCPL语言
外文名
C Programming Language
c语言简介
C语言是一门面向过程的计算机编程语言,与C++、Java等面向对象编程语言有所不同。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、仅产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。C语言描述问题比汇编语言迅速、工作量小、可读性好、易于调试、修改和移植,而代码质量与汇编语言相当。C语言一般只比汇编语言代码生成的目标程序效率低10%~20%。因此,C语言可以编写系统软件。 [2]  当前阶段,在编程领域中,C语言的运用非常之多,它兼顾了高级语言和汇编语言的优点,相较于其它编程语言具有较大优势。计算机系统设计以及应用程序编写是C语言应用的两大领域。同时,C语言的普适较强,在许多计算机操作系统中都能够得到适用,且效率显著。 [3]  冯.诺依曼在1945年提出了现代计算机的若干思想,被后人称为冯.诺依曼思想,这是计算机发展史上的里程碑。自1945 年至今大多采用其结构,因此冯.诺依曼被称为计算机之父。他的体系结构计算机由运算器、控制器、存储器、输入设备、输出设备五大部件构成。 C语言拥有一套完整的理论体系经过了漫长的发展历史,在编程语言中具有举足轻重的地位。 [4] 
收起全文
精华内容
参与话题
  • C#泛型详解

    2018-07-13 14:37:24
    转载自:C#泛型详解这篇文章主要来讲讲c#中的泛型,因为泛型在c#中有很重要的位置,对于写出高可读性,高性能的代码有着关键的作用。一、什么是泛型?泛型是 2.0 版 C# 语言和公共语言运行库 (CLR) 中的一个非常重要...

    转载自:C#泛型详解

    这篇文章主要来讲讲c#中的泛型,因为泛型在c#中有很重要的位置,对于写出高可读性,高性能的代码有着关键的作用。

    一、什么是泛型?

    泛型是 2.0 版 C# 语言和公共语言运行库 (CLR) 中的一个非常重要的新功能。

    我们在编程程序时,经常会遇到功能非常相似的模块,只是它们处理的数据不一样。但我们没有办法,只能分别写多个方法来处理不同的数据类型。这个时候,那么问题来了,有没有一种办法,用同一个方法来处理传入不同种类型参数的办法呢?泛型的出现就是专门来解决这个问题的,可以看出,微软还是很贴心的。

    二、为什么要使用泛型?

    接下来我们来看一段代码。

    复制代码
    public class GenericClass
        {
            public void ShowInt(int n)
            {
                Console.WriteLine("ShowInt print {0},ShowInt Parament Type Is {1}",n,n.GetType());
            }
            public void ShowDateTime(DateTime dt)
            {
                Console.WriteLine("ShowDateTime print {0},ShowDateTime Parament Type Is {1}", dt, dt.GetType());
            }
            public void ShowPeople(People people)
            {
                Console.WriteLine("ShowPeople print {0},ShowPeople Parament Type Is {1}", people, people.GetType());
            }
        }
    复制代码
    复制代码
     static void Main(string[] args)
            {
                GenericClass generice = new GenericClass();
                generice.ShowInt(11);
                generice.ShowDateTime(DateTime.Now);
                generice.ShowPeople(new People { Id = 11, Name = "Tom" });
    
                Console.ReadKey();
            }
    复制代码
     

    显示结果:

     我们可以看出这三个方法,除了传入的参数不同外,其里面实现的功能都是一样的。在1.1版的时候,还没有泛型这个概念,那么怎么办呢。就有人想到了OOP三大特性之一的继承,我们知道,C#语言中,所有类型都源自同一个类型,那就是object。

     View Code

    显示结果:

    我们可以看出,目地是达到了。解决了代码的可读性,但是这样又有个不好的地方了,我们这样做实际上是一个装箱拆箱操作,会损耗性能。

    终于,微软在2.0的时候发布了泛型。接下来我们用泛型方法来实现该功能。

    三、泛型类型参数

    在使用泛型方法之前,我们先来了解下有关于泛型的一些知识。

    在泛型类型或方法定义中,类型参数是在其实例化泛型类型的一个变量时,客户端指定的特定类型的占位符。 泛型类( GenericList<T>)无法按原样使用,因为它不是真正的类型;它更像是类型的蓝图。 若要使用 GenericList<T>,客户端代码必须通过指定尖括号内的类型参数来声明并实例化构造类型。 此特定类的类型参数可以是编译器可识别的任何类型。 可创建任意数量的构造类型实例,其中每个使用不同的类型参数,如下所示:

    GenericList<float> list1 = new GenericList<float>();
    GenericList<ExampleClass> list2 = new GenericList<ExampleClass>();
    GenericList<ExampleStruct> list3 = new GenericList<ExampleStruct>();

    在 GenericList<T> 的每个实例中,类中出现的每个 T 在运行时均会被替换为类型参数。 通过这种替换,我们已通过使用单个类定义创建了三个单独的类型安全的有效对象。 

    三、泛型约束

    定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的几种类型施加限制。 如果客户端代码尝试使用约束所不允许的类型来实例化类,则会产生编译时错误。 这些限制称为约束。 通过使用 where 上下文关键字指定约束。 下表列出了六种类型的约束:

    where T:结构(类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。)

    复制代码
    class MyClass<U>
            where U : struct///约束U参数必须为“值 类型”
     { }
    
     public void MyMetod<T>(T t)
           where T : struct
     {          
     }
    复制代码

    where T:类(类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。)

    复制代码
    class MyClass<U>
            where U : class///约束U参数必须为“引用类型”
     { }
    
     public void MyMetod<T>(T t)
           where T : class
     {          
     }
    复制代码

    where T:new()(类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。)

    class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
    {
        // ...
    }

    where T:<基类名>(类型参数必须是指定的基类或派生自指定的基类。)

    public class Employee{}
    
    public class GenericList<T> where T : Employee

    where T:<接口名称>(类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。)

    复制代码
     /// <summary>
        /// 接口
        /// </summary>
        interface IMyInterface
        {
        }
    
        /// <summary>
        /// 定义的一个字典类型
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TVal"></typeparam>
        class Dictionary<TKey, TVal>
            where TKey : IComparable, IEnumerable
            where TVal : IMyInterface
        {
            public void Add(TKey key, TVal val)
            {
            }
        }
    复制代码

    where T:U(为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。也就是说T和U的参数必须一样)

    class List<T>
    {
        void Add<U>(List<U> items) where U : T {/*...*/}
    }

    以上就是对六种泛型的简单示例,当然泛型约束不仅仅适用于类,接口,对于泛型方法,泛型委托都同样适用。

    三、泛型方法

    复制代码
    public class GenericClass
        {
            public void ShowT<T>(T t)
            {
                Console.WriteLine("ShowT print {0},ShowT Parament Type Is {1}", t, t.GetType());
            }
        }
    static void Main(string[] args)
            {
                Console.WriteLine("*****************泛型方法调用*********************");
                generice.ShowT<int>(11);
                generice.ShowT<DateTime>(DateTime.Now);
                generice.ShowT<People>(new People { Id = 11, Name = "Tom" });
    
                Console.ReadKey();
            }
    复制代码

    显示结果:

    也是一样的,现在终于实现了我们想要达到的效果了。我们可以看出,无论是什么方式调用,最后我们获取出来的类型都是原始类型。我们知道,用object获取是利用了继承这一特性,当编译器编译的时候,我们传入的参数会进行装箱操作,当我们获取的时候又要进行拆箱操作,这个方法会损耗性能 。那么泛型方法实现的原理又是怎样的呢?首先,我们要知道,泛型是一个语法糖,在我们调用泛型方法,编译器进行编译时,才会确定传入的参数的类型,从而生成副本方法。这个副本方法与原始方法一法,所以不会有装箱拆箱操作,也就没有损耗性能这回事了。

    四、泛型类

    泛型类封装不特定于特定数据类型的操作。

    通常,创建泛型类是从现有具体类开始,然后每次逐个将类型更改为类型参数,直到泛化和可用性达到最佳平衡。

    创建自己的泛型类时,需要考虑以下重要注意事项:

    • 要将哪些类型泛化为类型参数。

                   通常,可参数化的类型越多,代码就越灵活、其可重用性就越高。 但过度泛化会造成其他开发人员难以阅读或理解代码。

    • 要将何种约束(如有)应用到类型参数

     

             其中一个有用的规则是,应用最大程度的约束,同时仍可处理必须处理的类型。 例如,如果知道泛型类仅用于引用类型,则请应用类约束。 这可防止将类意外用于值类型,并     使你可在   T  上使用  as  运算符和检查 null 值。      

     

    • 是否将泛型行为分解为基类和子类。

      因为泛型类可用作基类,所以非泛型类的相同设计注意事项在此也适用。 请参阅本主题后文有关从泛型基类继承的规则。

    • 实现一个泛型接口还是多个泛型接口。

    复制代码
    class BaseNode { }
    class BaseNodeGeneric<T> { }
    
    // concrete type
    class NodeConcrete<T> : BaseNode { }
    
    //closed constructed type
    class NodeClosed<T> : BaseNodeGeneric<int> { }
    
    //open constructed type 
    class NodeOpen<T> : BaseNodeGeneric<T> { }
    复制代码

    五、泛型接口

    • 定义一个泛型接口:
    interface IMyGenericInterface<T>
    {
    }
    • 一个接口可定义多个类型参数,如下所示:
    interface IMyGenericInterface<TKey,TValue>
    {
    }
    • 具体类可实现封闭式构造接口,如下所示:
    interface IBaseInterface<T> { }
    
    class SampleClass : IBaseInterface<string> { }//如果T有约束,那么string类型必须得满足T的约束

    六、泛型委托

    委托可以定义它自己的类型参数。 引用泛型委托的代码可以指定类型参数以创建封闭式构造类型,就像实例化泛型类或调用泛型方法一样,如以下示例中所示:

    复制代码
     class Program
        {
            static void Main(string[] args)
            {
                Del<int> m1 = new Del<int>(Notify);
                m1.Invoke(1111);
                Del<string> m2 = new Del<string>(Notify);
                m2.Invoke("字符串");
    
                Console.ReadKey();
            }
    
            public delegate void Del<T>(T item);
            public static void Notify(int i) { Console.WriteLine("{0} type is {1}", i,i.GetType()); }
            public static void Notify(string str) { Console.WriteLine("{0} type is {1}", str, str.GetType()); }
           
        }
    复制代码

    运行结果:

     

    七、泛型代码中的默认关键字:Default

    在泛型类和泛型方法中产生的一个问题是,在预先未知以下情况时,如何将默认值分配给参数化类型 T:

    • T 是引用类型还是值类型。

    • 如果 T 为值类型,则它是数值还是结构。

    给定参数化类型 T 的一个变量 t,只有当 T 为引用类型时,语句 t = null 才有效;只有当 T 为数值类型而不是结构时,语句 t = 0 才能正常使用。解决方案是使用 default 关键字,此关键字对于引用类型会返回空,对于数值类型会返回零。对于结构,此关键字将返回初始化为零或空的每个结构成员,具体取决于这些结构是值类型还是引用类型。

    复制代码
    namespace MyGeneric
    {
        class Program
        {
            static void Main(string[] args)
            {
                object obj1=GenericToDefault<string>();
                object obj2 = GenericToDefault<int>();
                object obj3 = GenericToDefault<StructDemo>();
                Console.ReadKey();
            }
            public static T GenericToDefault<T>() 
            {
                return default(T);
            }
        }
        public struct StructDemo
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
    }
    复制代码

    运行结果:

     

    展开全文
  • 泛型集合和ArrayList的装箱拆箱、常见的泛型类型、泛型类和泛型方法、泛型约束、 泛型委托泛型很难理解?不然在接触的一个新的概念的时候,总会感觉难以理解,当你掌握并能熟练地使用的时候,发现这个概念其实简单...

    前文传送门,dotNET开发基础汇总系列
    StackOverflow 20万阅读的问题:如何实现异步Task超时的处理
    Func和Action委托简单用法
    C#异步编程基础入门总结
    C#泛型入门学习泛型类、泛型集合、泛型方法、泛型约束、泛型委托
    C#异常处理总结

    ###本章阅读列表###

    • 泛型很难理解?不然
    • 泛型集合和ArrayList的装箱拆箱
    • 常见的泛型类型
    • 泛型类和泛型方法
    • 泛型约束
    • 泛型委托

    ###泛型很难理解?不然 ###
    在接触的一个新的概念的时候,总会感觉难以理解,当你掌握并能熟练地使用的时候,发现这个概念其实简单的,我相信大多数码农都会有这种似曾相识的感觉。可能大多数人刚学习泛型的时候觉得很难理解,当然我也是这样的,所以便写下这篇文章加深一下对泛型的印象。
    第一次接触泛型那还是在大二上学期的时候,那会是学c#面向对象的时候接触过泛型集合,但尴尬的是那会还没有“泛型”这个概念,仅仅只停留在泛型集合的使用。关于泛型入门的文章csdn和博客园有很多,这里我也写一篇关于我对泛型学习的一个总结,如果出现错误表达不当的地方,还希望评论指出。
    ###泛型优点###
    官方文档:https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/generics/introduction-to-generics
    简介:
    泛型是.NET Framework2.0新增的一个特性,在命名空间System.Collections.Generic,包含了几个新的基于泛型的集合类,官方建议.net 2.0 及更高版本的应用程序使用心得泛型集合类,而不使用非泛型集合类,例如ArrayList。
    官方解释:
    泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。各种程序设计语言和其编译器、运行环境对泛型的支持均不一样。将类型参数化以达到代码复用提高软件开发工作效率的一种数据类型。泛型类是引用类型,是堆对象,主要是引入了类型参数这个概念。
    泛型的定义主要有以下两种:
    1.在程序编码中一些包含类型参数的类型,也就是说泛型的参数只可以代表类,不能代表个别对象。(这是当今较常见的定义)
    2.在程序编码中一些包含参数的类。其参数可以代表类或对象等等。(人们大多把这称作模板)不论使用哪个定义,泛型的参数在真正使用泛型时都必须作出指明
    官方的解释虽然很难理解,用我的话来解释那就是,声明类和方法时一般都需要定义是什么类,class Brid ,Class Food… 声明泛型类和方法时只需要传入类型的地方用 ,有点类似于占位符的作用,用的时候传入具体的类型。当针对不同类型具有相同行为的时候,也就是泛型发挥作用的时候。
    优点:
    1.使用泛型类、方法,我们可以极大提高代码的重用性,不需要对类型不同代码相同(仅类型参数不同)的代码写多次。
    2.创建泛型类,可在编译时创建类型安全的集合
    3.避免装箱和拆箱操作降低性能,在大型集合中装箱和拆箱的影响非常大.

    泛型集合和ArrayList的装箱拆箱###

    装箱:是指从值类型转换成引用类型
    拆箱:是指从引用类型转换成值类型
    下面的例子是借鉴官方的一段代码:

        System.Collections.ArrayList list1 = new System.Collections.ArrayList();
                list1.Add(3);
                list1.Add(105);
    
                System.Collections.ArrayList list2 = new System.Collections.ArrayList();
                list2.Add("科比");
                list2.Add("詹姆斯");
    

    ArrayList是一个极为方便的集合类,可以用于存储任何引用或值类型。但是缺点也很明显,第一个缺点是编译的时候不会检查类型,例如

      System.Collections.ArrayList list1 = new System.Collections.ArrayList();
                list1.Add(3);
                list1.Add(105);
                list1.Add("sd");
                foreach (int item in list1)
                {
                    Console.WriteLine(item.ToString());
                }
    

    编译正常,运行的时候会出现转换类型错误。
    至于ArrayList第二个缺点就是装箱拆箱的时候回造成性能的损失。我们看看ArrayList的Add方法的定义。
    这里写图片描述
    参数是一个object类型,也就是说ArrayList添加任何引用类型或值类型都会隐士转换成Object,这个时候便发生装箱操作,在遍历检索它们时必须从object 类型转换成指定的类型,这个时候便发生拆箱操作。这两种操作会大大降低性能。所以.net 2.0的程序时应该放弃使用ArrayList,推荐使用使用List《T》 泛型集合。这也是我们为什么要使用泛型的原因之一。

    ###常见的泛型类型###
    在泛型类型的定义中,出现的每个T(一个展位变量而已叫别的名字也行)在运行时都会被替换成实际的类型参数。下面是一些基础的泛型类型
    1.泛型类

               class MyGenericClass<T>
            {
              //......
            }
    

    2.泛型接口

            interface  GenericInterface<T>
            {
               void  GenericMethod(T t);
            }
    

    3.泛型方法

            public void MyGenericMethod<T>()
            {
              //......
            }
    

    4.泛型数组

    public T[] GenericArray;
    

    5.泛型委托

     public delegate TOutput GenericDelagete<TInput, TOutput>(TInput input);
    

    6.泛型结构

       struct MyGenericStruct<T>
            {
    
            }
    

    在使用时所有的T的都要替换成具体的类型。
    类型参数命名指南,参见官方文档
    这里写图片描述
    ###泛型类和泛型方法###
    我们先来看看泛型方法,这个方法的用途是来交换两个变量的

            static void Main(string[] args)
            {
                int a = 1;
                int b = 2;
                SwapInt(ref a,ref b);
                Console.WriteLine($"a={a}b={b}");
            }
            public static void SwapInt(ref int a, ref int b)
            {
                int temp;
                temp = a;
                a = b;
                b = temp;
            }
    

    结果是a=2,b=1,但是我们现在要换成string类型呢,是不是得再写一个string参数的方法呢,如果是char、double…,这每个不同类型的参数都要写一个参数,的确太麻烦并且没有这个必要,Object ?当然可以

            static void Main(string[] args)
            {
                object a = 1;
                object b = 2;
                SwapObject(ref a,ref b);
                Console.WriteLine($"a={a}b={b}");
            }
            public static void SwapObject(ref object a, ref object b)
            {
                object temp;
                temp = a;
                a = b;
                b = temp;
            }
    

    这确实能解决代码复用的需求,但是上面我们已经知道使用Object类型会发生装箱拆箱的操作,会降低性能。所以我们可以使用泛型方法解决这个缺点。

        static void Main(string[] args)
            {
                int a = 1;
                int b = 2;
                SwapGeneric(ref a,ref b);
                Console.WriteLine($"a={a}b={b}");
            }
            //交换两个变量的方法
            public static void SwapGeneric<T>(ref T a, ref T b)
            {
                T temp;
                temp = a;
                a = b;
                b = temp;
            }
    

    泛型类:这个泛型类常用api通用接口的泛型类。

        class Program
        {
            static void Main(string[] args)
            {
                List<Product> data = new List<Client.Product>() {
                                  new Client.Product() { Id=12,Name="土豆"},
                                  new Client.Product() { Id=12,Name="茄子"},
                                  new Client.Product() { Id=12,Name="黄瓜"}
               };
               var resultProduct = Result<Product>.Success(data);
                var resultUser = Result<User>.Error("没有数据");
                foreach (var item in resultProduct.Data)
                {
                    Console.WriteLine(item.Id+","+item.Name);
                }
                Console.WriteLine(resultUser.IsSuccess+resultUser.Message);
            }
    
        }
        public class Result<T> { //泛型类,声明T变量类型
            public bool IsSuccess { get; set; }
            public List<T> Data { get; set;}//未定义具体类型的泛型集合
            public string Message { get; set; }
            public static Result<T> Error(string message) 
            {
                return new Client.Result<T> { IsSuccess = false, Message = message };
            }
            //泛型方法,初始化数据
            public static Result<T> Success(List<T> data)
            {
                return new Client.Result<T> { IsSuccess =true,Data =data}; //成功就没有提示消息的原则
            }
        }
        public class Product {
            public int Id { get; set; }
            public string Name { get; set; }
        }
        public class User {
            public int Age { get; set; }
            public string Name { get; set; }
        }
    

    使用该通用的泛型类的好处在于,获取不同的对象集合不需要写多个方法,获取Product数据集合、获取User数据集…。只需要调用Success方法既可,使代码变得可复用。
    ###泛型类型参数约束###
    为什么要使用类型参数的约束呢,简单点说就是筛选类型参数,在使用泛型的代码中如果违反了某个约束不允许的类型来实例化则会产生编译错误,类型参数的约束是使用关键字where。 下面列出了6中类型的约束

    1. where T: struct
      类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。有关更多信息,请参见使用可以为 null 的类型(C# 编程指南)。
    2. where T : class
      类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。
    3. where T:new()
      类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。
    4. where T:<基类名>
      类型参数必须是指定的基类或派生自指定的基类。
    5. where T:<接口名称>
      类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
    6. where T:U
      为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。
      我们在看看上面那个交换两个变量的方法SwapGeneric,加上必须是值类型的约束
      public static void SwapGeneric<T>(ref T a,ref T b) where T :struct 
            {
                T temp;
                temp = a;
                a = b;
                b = a;
            }
            //实例化
                Product p = new Product() { Id=1,Name="土豆"};
                Product p1 = new Product() { Id=2,Name ="茄子"};
                SwapGeneric<Product>(ref p,ref p1);
    

    我们在使用的时候编译给我们提示了以下的错误:
    这里写图片描述
    “类型Product必须是不可以为NUll值得类型”,引用类型的默认值就是NULL,所以该房型方法的类型参数不能是引用类型,这就是使用类型参数约束的好处。
    约束多个参数

        class List<TLive,U> where TLive:User where U:struct
        {
    
        }
    

    ###泛型委托###
    泛型委托可以自己定义自己的类型参数,声明的时候还是和泛型类、泛型方法一样加个<坑> 站个坑,其实泛型委托使用的时候不是很多,要慎用。,如以下事例

    public delegate T DelegateGeneric<T>(T item);
    DelegateGeneric<string> test = StringMethod;
            public static string StringMethod(string name)
            {
                return "你好" + name;
            }
    

    将上面的交换两个变量的方法改成委托是这样的

            public delegate void DelegateGenericSwap<T>(ref T a,ref T b);
                string a = "张林";
                string b = "科比";
                DelegateGenericSwap<string> swap = GenericSwap;
                Console.WriteLine($"a:{a}b:{b}");
               public static void GenericSwap<T>(ref T a,ref T b)
            {
                T temp;
                temp = a;
                a = b;
                b = a;
            }
    

    作者信息
    【文章信息】:作者-张林:原文链接-https://blog.csdn.net/kebi007/article/details/77800954
    【原创公众号】:dotNet全栈开发。好文目录
    版权声明:本文为CSDN博主「dotNet全栈开发」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

    展开全文
  • C#泛型应用及原理

    千次阅读 2019-08-19 14:03:04
    泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性。泛型为.NET框架引入了类型参数(type parameters)的概念。类型参数使得设计类和方法时,不必指定方法有一个或多个具体参数,而是在调用方法的时候...

    泛型(generic)是C#语言2.0和通用语言运行时(CLR)的一个新特性。泛型为.NET框架引入了类型参数(type parameters)的概念。类型参数使得设计类和方法时,不必指定方法有一个或多个具体参数,而是在调用方法的时候再去指定。这意味着使用泛型的类型参数T,写一个方法MyList<T>,客户代码可以这样调用:MyList<int>, MyList<string>或 MyList<MyClass>,也就是说一个方法就可以满足不同场景的使用。避免了运行时类型转换或装箱操作的代价和风险。

    为什么要有泛型,什么时候才需要用到泛型?

    针对早期版本的通用语言运行时和C#语言的局限,泛型提供了一个解决方案。以前类型的泛化(generalization)是靠类型与全局基类System.Object的相互转换来实现。比如.NET框架基础类库的ArrayList容器类,就是这种局限的一个例子。ArrayList是一个很方便的容器类,使用中无需更改就可以存储任何引用类型或值类型。

    相对于数组来说,这种集合比数组灵活(数组长度固定,数据类型单一),但是这种便利是有代价的,这需要把任何一个加入ArrayList的引用类型或值类型都隐式地向上转换成System.Object(如上图所示)。如果这些元素是值类型,那么当加入到列表中时,它们必须被装箱;当重新取回它们时,要拆箱。类型转换和装箱、拆箱的操作都降低了性能;在必须迭代(iterate)大容器的情况下,装箱和拆箱的影响可能十分显著。

    另一个局限是缺乏编译时的类型检查,比如当用户需要保存用户的年龄时,结果把用户的姓名也存进去了,但是因为ArrayList把任何类型都转换为Object,所以编译的时候不会报错,这个错误只有在程序运行过程中才会暴露出来。

    ArrayList和其他相似的类真正需要的是一种途径,能让客户代码在实例化之前指定所需的特定数据类型。这样就不需要向上类型转换为Object,而且编译器可以同时进行类型检查。换句话说,ArrayList需要一个类型参数。这正是泛型所提供的。在System.Collections.Generic命名空间中的泛型List<T>容器里,同样是把元素加入容器的操作,类似这样:

    如上图所示,与ArrayList相比,List<T>创建的集合比ArrayList更安全,比如定义的是int类型的约束,如果输入“张珊”的字符串就会直接报错,而且不需要做装箱的操作。并且List<T>可以定义各种类型的集合,通俗的来说就是一个方法可以完成多种功能。

    总结下,当我们程序代码有相同的逻辑,有可能是方法、接口、类或者委托,只是某些参数类型不同,我们希望代码可以通用、复用,甚至是说为了偷懒,也可以说是在不确定类型的情况下,就应该考虑用泛型的思维去实现。

    泛型在方法、接口、类、委托中的实现方式

    在泛型类型或泛型方法的定义中,类型参数是一个占位符(placeholder),通常为一个大写字母,如List<T>中的T。在客户代码声明、实例化该类型的变量时,把T替换为客户代码所指定的数据类型,当然这个T可以改为A、B、C等。C#中可以定义泛型方法、泛型接口、泛型类和泛型委托。

    泛型类

    public class BaseDal<T>: SixcomHelper where T : class, new()
    {
       /// <summary>
       /// 查询对象(完整sql)
       /// </summary>
       /// <typeparam name="T"></typeparam>
       /// <param name="sql"></param>
       /// <returns></returns>
       public List<T> GetBySql<T>(string sql)
       {
           return GetList<T>(sql).ToList();
       }
    
       /// <summary>
       /// 查询单个实体
       /// </summary>
       /// <typeparam name="T">实体</typeparam>
       /// <param name="sql">sql</param>
       /// <returns></returns>
       public T GetOneBySql<T>(string sql)
       {
           var Data = GetList<T>(sql).ToArray();
           if (Data != null && Data.Length > 0)
           { return Data[0]; }
           return default(T);
       }
    }

    泛型方法

    //通过订单表唯一标识值-修改订单状态
    public Tuple<int, string> UpdatePayStatus<T>(T Parameter)
    {
        int Return_Result = 0;//0是成功
        string Return_Msg = "ok";//返回提示
        string Sql_Execute = string.Empty;
        try {
               string TypeName = typeof(T).Name;
               if (TypeName == "Int32")
               {
                   Sql_Execute = $"Update Order set Status=1 where Id={Parameter};";
               }
               else if (TypeName == "String")
               {
                   Sql_Execute = $"Update Order set Status=1 where OrderNum={Parameter};";
               }
    
               bool b = this.Execute(Sql_Execute);
               if (!b) {
                  Return_Result = 1;
                  Return_Msg = "执行失败";
               }
            }
         catch (Exception exMsg)
         {
             Return_Result = -1;
             Return_Msg = exMsg.Message;
         }
         return new Tuple<int, string>(Return_Result, Return_Msg);
    }

    泛型接口

    public interface IStore<W> {}
    //GenericStore类声明了2个类型参数T、W,泛型类可以直接实现泛型接口
    public class GenericStore<T, W> : IStore<W>{}

    泛型委托

    //定义有一个参数的泛型委托
    public delegate void GenericDelegate<T>(T item);
    //定义方法
    public static void FuncInfo(int i) { }
    //实例化
    GenericDelegate<int> m = new GenericDelegate<int>(FuncInfo);

    .NET框架类库给我们提供的泛型类或接口

    C#语言2.0版的.NET框架类库提供了一个新的命名空间,System.Collections.Generic,其中包含了一些已经可以使用的泛型容器类和相关的接口。和早期版本的.NET框架提供的非泛型容器类相比,这些类和接口更高效且是类型安全的。在设计、实现自定义的容器类之前,可以考虑使用或继承下图中的某一个。

    泛型类或接口

    描述

    对应的非泛型类型

    Collection<T>

    ICollection<T>

    为泛型容器提供基类

    CollectionBase

    ICollection

    Comparer<T>

    IComparer<T>

    IComparable<T>

    比较两个相同泛型类型的对象是否相等、可排序。

    Comparer

    IComparer

    IComparable

    Dictionary<K, V>

    IDictionary<K,V>

    表示用键组织的键/值对集合。

    Hashtable

    IDictionary

    Dictionary<K, V>.KeyCollection

    表示Dictionary<K, V>中键的集合。

    None.

    Dictionary<K, V>.ValueCollection

    表示Dictionary<K, V>中值的集合。

    None.

    IEnumerable<T>

    IEnumerator<T>

    表示可以使用foreach 迭代的集合。

    IEnumerable

    IEnumerator

    KeyedCollection<T, U>

    表示有键值的集合。

    KeyedCollection

    LinkedList<T>

    表示双向链表。

    None.

    LinkedListNode<T>

    表示LinkedList<T>中的节点。

    None.

    List<T>

    IList<T>

    使用大小可按需动态增加的数组实现 IList 接口

    ArrayList

    IList

    Queue<T>

    表示对象的先进先出集合。

    Queue

    ReadOnlyCollection<T>

    为泛型只读容器提供基类。

    ReadOnlyCollectionBase

    SortedDictionary<K, V>

     表示键/值对的集合,这些键和值按键排序并可按照键访问,实现IComparer<T>接口。

    SortedList

    Stack<T>

    表示对象的简单的后进先出集合。

    Stack

     

     

     

    展开全文
  • C#泛型与委托

    2015-11-15 12:21:05
    讲述C#泛型与委托的基本概念以及使用等

    C#泛型与委托


    时间:2015.10.28
    

    泛型

    定义

    • T
      • 可以作为各种类型进行使用,方便编程
    • 在函数中的定义

      private T MyFunc<T>(T a)
      {
          object tmp = a;
          if (a is int)
              return (T)((object)(Convert.ToInt32(tmp) * 3));
          else if (a is double)
              return (T)((object)(Convert.ToDouble(tmp) * 0.5));
          else
              return a;
      }
      
    • 如上,在泛型不能直接和其他类型的数据进行操作,需要先将泛型转化为转化为另外一个操作数的类型,之后转化为object,再强制转化为T(具体的类型不能直接转化为泛型)。

    委托

    定义

    • 直接定义如下即可
      • public delegate T Calculator(T x);
    • 对委托的函数定义如下:

      private T MyFunc<T>(T a)
      {
          if (a is int)
              return (T)((object)(Convert.ToInt32(a) * 3));
          else if (a is double)
              return (T)((object)(Convert.ToDouble(a) * 0.5));
          else
              return a;
      }
      
    • 只要和委托的参数类型相同,都可以作为委托的“实例化”
    • 具体的调用方法如下:

      int[] a = new int[] { 1, 3, 5 };
      MyUtility.Calculate<int>(a,MyFunc);
      

    作用

    • 实现插件式编程:可以执行任意一个参数形式相同的函数的方法

    多播委托

    • 一个委托可以指向不止一个方法,即可以实现多个方法,见下面的实例
    • 首先定义一个委托

      public delegate void ProgressReporter(int percent);

    • 按键响应事件如下:

      private void button4_Click(object sender, RoutedEventArgs e)
      {
          ProgressReporter p = null;
          p += WriteToConsole;
          p += WriteToFile;
          MyUtility.MyMatch(p);
          Console.WriteLine("finished");
      }
      static void WriteToConsole(int per)
      {
          Console.WriteLine(per+"%");
      }
      static void WriteToFile(int per)
      {
          System.IO.File.AppendAllText("E:/test.txt", per + "%\r\n");
      }
      
    • MyMatch定义如下:

      public static void MyMatch(ProgressReporter p)
      {
          if (p != null)
          {
              for (int i = 0; i <= 10; i++)
              {
                  p(i * 10);
                  Thread.Sleep(100);
              }
          }
      }
      

    Func和Action委托

    • 相同点:都是新的委托,接受多个参数,都是为了简化代码(不使用delegate),Func 和 Action 委托,除了ref参数和out参数,基本上能适用于任何泛型委托的场景
    • 不同点:Func有返回值,Action无返回值
    • Action委托示例如下:

      //使用了兼容的参数
      private void button5_Click(object sender, RoutedEventArgs e)
      {
          Action<object> action = null;
          action = MyAction;
          action(3);
      }
      
      private void MyAction(object a)
      {
          Console.WriteLine(a);
      }
      

      不用再用delegate定义委托,非常方便。

    委托的比较

    • 对于具体相同的目标方法的委托被视为相等;
    • 对于多播委托,相同的方法有对应的相同的顺序,则也被视为相等

    事件

    角色

    • 广播者:包括一个委托字段,通过调用委托发出广播
    • 订阅者:通过+=和-=的形式开始或者停止订阅

    定义

    • 直接在声明委托时加event关键字即可,如下

      public event PriceChangedHandler PriceChanged;
      

    实例分析

    • 以下是价格改变时会调用价格改变函数

    MyMobile的定义

    public class MyMobile
    {
        private int price = 0;
        public PriceChangedEventHandler priceChanged;
        public MyMobile(int p)
        {
            price = p;
        }
        public int Price
        {
            get
            {
                return price;
            }
            set
            {
                int oldPrice = price;
                this.price = value;
                priceChanged(oldPrice,price);
            }
        }
    }
    

    按键响应以及对应的价格改变函数

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            MyMobile m = new MyMobile(1000);
            m.priceChanged += changedP;
            m.Price = 500;
        }
    
        private void changedP(int o, int p)
        {
            if (o != p)
            {
                Console.WriteLine("ori: "+o+" , now: "+p);
            }
        }
    
    展开全文
  • c#: 泛型接口、泛型方法

    千次阅读 2018-01-04 14:29:05
    泛型可以自定义泛型接口、泛型类、泛型方法、泛型事件、泛型委托。 1>自定义泛型接口 和普通接口一样,一个泛型接口通常也是与某些对象相关的约定规程。泛型接口的声明如下: interface [接口名] { [接口体] } 在c#...
  • C#泛型

    千次阅读 2018-11-22 23:11:49
    文章目录泛型泛型泛型方法泛型的实例化理论泛型与object泛型类中的数据约束 泛型 在写程序时,若需要处理的数据类型不同,但算法相同时,这时候需要用到泛型泛型提供了编译时类型安全检测机制,该机制允许程序员...
  • C#泛型类定义和泛型方法定义

    千次阅读 2018-11-24 01:45:00
    泛型类定义 定义一个泛型类就是指的是,定义一个类,这个类中某些字段的类型是不确定的,这些类型可以在类构造的时候确定下来,举例: class ClassA&amp;lt;T&amp;gt;{ private T a; private T b; public ...
  • C#泛型编程

    千次阅读 2019-03-06 15:53:40
    泛型:通过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用。 例子代码: class Program { static void Main(string[] args) { int obj = 2; ...
  • C#】获取泛型的真实类型

    万次阅读 2017-05-10 16:34:48
    Type t = typeof(T)
  • C#】允许泛型方法返回空值Null

    万次阅读 2017-03-31 15:00:38
    泛型方法返回default(T)
  • C#泛型返回类型的方法如何返回

    千次阅读 2019-04-02 18:57:03
    核心代码return (T)(object)xxx; 示例代码如下: public static T GetUnitSettingById<T>(int id) where T : Setting { if (typeof(T).Equals(typeof(BodySetting))) { var body = BodyS...
  • C# 泛型的类型转换

    千次阅读 2020-05-25 20:06:05
    有时候,我们需要在类中使用泛型,需要计算的时候,也是可以进行类型转换的。 以下举个例子来说明一下转换过程。 var converter = TypeDescriptor.GetConverter(typeof(TWeight)); 先用上述语句得到一个converter。...
  • C#泛型的初始化

    千次阅读 2016-04-02 11:44:31
    泛型的初始化:泛型是需要进行初始化的。使用T doc = default(T)以后,系统会自动为泛型进行初始化。 2、使用System.Activator.CreateInstance()对T为类的时候进行初始化 当T为类的时候,使用System.Activator...
  • C# Type传参转换成泛型T

    千次阅读 2015-04-17 16:29:04
    示例代码 public class Test{ public void Export() { } public void ExportByClassName(string typename1,string typename2) { Type t1 = Type.GetType(typename1); Type
  • C++的模板类可以设置类型的默认值:Template, class T2 = int> class ...我想问下C#的该怎么设置呢? public class Test2, T2> {} 我想让T2也有默认值为int类型,但是不知道怎么去设置……C#能不能设置呢? 谢谢大神,
  • c#根据属性名称获取泛型的属性值

    千次阅读 2018-05-17 18:11:00
    /// &lt;summary&gt; /// 根据属性名称获取属性值 /// &lt;/summary&gt; /// &lt;param name="entity"&gt;实体&lt;/param&gt; /// &lt;param name=".../p
  • C#泛型类的定义

    千次阅读 2018-04-23 10:49:12
    泛型 通过参数化类型来实现在同一份代码上操作多种数据类型。 利用“参数化类型”将类型抽象化,从而实现灵活的复用。 泛型类的定义 定义一个泛型类指的是,定义一个类,这个类中某些字段的类型是不确定的,这些...
  • C#泛型集合List自带方法之排序

    千次阅读 2013-12-11 17:10:33
    List list=new List(); list.OrderBy(t => t.SendTime).ToList() 使用拉姆达表达式。 list.OrderBy(t=>t.SendTime)结果显示是linq的类型。...我用list.OrderBy(t=>t.SendTime) as model和Modle(list.OrderBy(t=>...
  • /// /// 将字符串转化为指定类型 /// /// 指定的类型 /// 需要转换的字符串 /// <returns></returns> pub
  • 利用反射给泛型 实例化 和 给泛型属性赋值 public IList Tlist(DataTable dt)  {  IList tlist = new List();  if (dt.Rows.Count > 0)  {  System.Type t = typeof(T);
1 2 3 4 5 ... 20
收藏数 49,269
精华内容 19,707
关键字:

c#泛型