zoukankan      html  css  js  c++  java
  • [AaronYang]C#人爱学不学[4]

    本文章不适合入门,只适合有一定基础的人看。我更相信知识细节见高低,我是从4.0开始学的,终于有时间系统的学习C#5.0,是5.0中的知识,会特殊标记下。但写的内容也可能含有其他版本framework的知识,也是为了方便自己更好的记忆C#知识。文章内容都是自己总结,无抄袭,如果你觉得文章档次太低,请大牛绕道 --Aaronyang的博客(www.ayjs.net)

    1. 泛型-是C#的泛型

     1.1 性能方面比非泛型好点,比如拆箱装箱的问题。个人感觉代码可读性更好吧。还有就是 写代码可能可以写出很精彩的代码。命名用T开头,加有意义的单词,比如 Converter<TInput,TOut>,XX<TKey,TValue>

     1.2 题目:不百度,请自己至少列举5个 例如List<T>使用泛型的C#中的常用对象

     1.3 自己写个链式,并使用泛型知识的demo

           1.定义链式节点, 前一个节点,后一个节点,再加上自己这个节点就OK了 

       //定义链式节点, 前一个节点,后一个节点,再加上自己这个节点就OK了
        public class MyLinkedNode<T> { 
    
            public MyLinkedNode(T value){
                this.Value = value;
            }
            public T Value{get;private set;}
    
            /// <summary>
            /// 前一个节点对象
            /// </summary>
            public MyLinkedNode<T> Prev { get; internal set; }
            /// <summary>
            /// 后一个节点对象
            /// </summary>
            public MyLinkedNode<T> Next { get; internal set; }
    
        }

         2.接下来,在封装一个对节点的操作的操作类,正好复习 迭代器yield和理解IEnumerable<T>这个接口,时间有限,这里我只先实现AddLast和GetEnumerator

     //接下来,因为链式结构,只适合从尾部和首部增加元素,中间不方便增加元素。所以对节点的操作的封装类,一般 首部增加一个节点AddFirst(),尾部增加一个节点AddEnd()
        //移除一个节点RemoveFirst(),RemoveEnd(),这里我只先实现AddEnd和GetEnumerator
        public class MyLinkedList<T> : IEnumerable<T>
        {
    
            /// <summary>
            /// 默认 IEnumerable定义的,必须实现
            /// </summary>
            /// <returns></returns>
            public IEnumerator<T> GetEnumerator()
            {
                //使用yield,把MyLinkedNode<T>返回到IEnumerator中去
                MyLinkedNode<T> cur = First;
                while (cur!=null)    //如果下一个节点不为空
                {
                    yield return cur.Value;
                    cur = cur.Next;//把当前值设置成下一个节点的值
                }
            }
    
            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
    
            /// <summary>
            /// 添加一个节点,默认都是从尾部增加的
            /// </summary>
            /// <param name="myLinkedNode">MyLinkedNode中类型的值</param>
            /// <returns></returns>
            public MyLinkedNode<T> AddEnd(T myLinkedNode)
            {
                MyLinkedNode<T> cur = new MyLinkedNode<T>(myLinkedNode);
                if (First == null)
                {  
                    //如果该集合一个节点也没有,那么第一个和最后一个节点就等于当前节点
                    First = End = cur;
                }
                else { 
                 //因为尾部新节点增加,原来上次的尾部的节点就变成了该节点的前一个节点了,他自己变成了最后一个节点
                    MyLinkedNode<T> prevEnd = End;
                    //更新新的最后一个元素
                    End.Prev = prevEnd;
                    End.Next = cur;
                    End = cur;
                }
                return cur;
            }
    
            //在链式结构里面都有 第一个节点和最后一个节点的特殊节点
            /// <summary>
            /// MyLinkedList集合中第一个元素
            /// </summary>
            public MyLinkedNode<T> First { get; private set; }
            /// <summary>
            /// MyLinkedList集合中最后一个元素
            /// </summary>
            public MyLinkedNode<T> End { get; private set; }
    
            /// <summary>
            /// 在开始的地方增加一个节点
            /// </summary>
            /// <param name="myLinkedNode">MyLinkedNode值</param>
            /// <returns></returns>
            public MyLinkedNode<T> AddFirst(T myLinkedNode)
            {
                throw new NotImplementedException();//自己实现
            }
            /// <summary>
            /// 移除一个节点
            /// </summary>
            /// <param name="myLinkedNode">MyLinkedNode对象</param>
            /// <returns></returns>
            public MyLinkedNode<T> RemoveEnd(T myLinkedNode)
            {
                throw new NotImplementedException();//自己实现
            }
    
        }

           3.使用这个数据结构的集合

     class Program
        {
            static void Main(string[] args)
            {
                MyLinkedList<int> m = new MyLinkedList<int>();
                m.AddEnd(1);
                m.AddEnd(10);
                m.AddEnd(100);
                foreach (var item in m)
                {
                    Console.WriteLine(item+",");
                }
                Console.ReadLine();
            }
        }

    效果

     整个过程来说,感觉还是挺有意义的,特别当泛型的概念融入其中,你的代码可能更精彩。

     1.4 一些数据结构的类型,只是加深印象: Queue<T>,Dictionary<TKey, TValue>, ILookup(TKey, TElement) 等

     1.5 泛型默认值初始化,举个例子      public T GetT(){ T t=default(T);  ...     }

     1.6 泛型约束与继承:

           public abstract class Class1<T> :TEnumerable<T>

           public class DBManager<TDb> where TDb:ICommonDb,new()

           Aaronyang拓展: where T:struct / class  / 接口  / new() 构造函数约束,指定类型T必须有一个默认构造函数 /  其他泛型,例如  where T1:T2

     *1.7 静态成员:AaronYang讲解:只要记得 T 不一样,里面的静态成员的值是不共享的,也不会受影响。   专业术语:泛型类的静态成员只能在类的一个实例中共享

          自己写了一个例子,一看就懂了

     class Program
        {
            static void Main(string[] args)
            {
                OwnStaticGeneric1<string>.obj = 4;
                OwnStaticGeneric1<int>.obj = 5;
                OwnStaticGeneric1<string>.obj = 6;
                OwnStaticGeneric1<int>.obj = 7;
                Console.WriteLine(OwnStaticGeneric1<string>.obj);//   =>6
                Console.WriteLine(OwnStaticGeneric1<int>.obj); // =>7
    
    
                OwnStaticGeneric2<string>.obj = "4";
                OwnStaticGeneric2<int>.obj = 5;
                OwnStaticGeneric2<string>.obj = "6";
                OwnStaticGeneric2<int>.obj = 7;
                Console.WriteLine(OwnStaticGeneric1<string>.obj);//   =>6
                Console.WriteLine(OwnStaticGeneric1<int>.obj); // =>7
    
    
                Console.ReadLine();
            }
        }
    
        public class OwnStaticGeneric1<T> {
            public static int obj;
        }
    
        public class OwnStaticGeneric2<T>
        {
            public static T obj;
        }

     1.8 高级知识: 泛型接口,感觉让你考架构师的样子

        1.8.1  拓展一下 可能会使用的 跟 ref和out差不多性质的  in(in修饰的参数,在方法体内的过程不会改写in的参数的值)关键字用法。如果不太懂,可以百度,也可以看我下面的例子,但提前,你最好懂out,ref的基础用法。

                  有些人设计接口直接    IInterface<T1,T2>,其实也还有很奇妙的其他写法,用 in或者out或者ref 修饰泛型的场景

              讲解: 一个SubClass类实现了ITestIn接口,out定义输出类型,in定义输入类型,必须是把值输入,所以莫名的 ITestIn<string,object> 一下子就懂了。还不懂的话,建议你百度

              留个题目:如何 让用户写代码可以写出如下的效果,Student的值是不允许改变的,请设计接口

              public class Student:ICustomComparable<Student>{

                    public int CompareTo(Student stu){

                        return ... ;

                    }

              }

              参考部分答案(答案字体被我设置成白色了,查看的,自己选择后面的空白部分): public interface ICustomComparable<in T>{     int    CompareTo(T stu);   }

                

         1.8.2  其实上面的 in或者out修饰泛型,涉及到了泛型知识中的 协变(泛型参数被out修饰)与抗变(泛型参数被in修饰)的知识,不要太在意,会用就好!!!!!!oh! shit,抗英(国)

    1.9 Nullable<T>      T必须是值类型,定义可为空,有兴趣的可以看看 public struct Nullable<T> where T:struct的实现

          等同写法:       Nullable<int>    a   等同于  int? a

          ?? 的用法: 例如 int y=x ?? 0;   如果x为null,则等于0,否则就是原值。

    1.10 当然泛型也可以像用在类上那样用于方法上,这个知识太简单,不讲了

    1.11 泛型委托,Lambda表达式最多,典型的有比如Func  Action等,这些在LINQ里再讲

    1.12 作为一年以上的开发人员,都知道的我都跳过了,可能存在疑问的地方保留了。

    ======安徽六安=========www.ayjs.net==========aaronyang========杨洋==================

  • 相关阅读:
    摄像头标定
    利用opencv的FileStorage类实现XML/YAML文件的读写
    VS2012在一个解决方案中添加多个项目(工程)
    Complainer sucks!
    Artificial Intelligence
    《Fast Traking via Spatio-Temporal Context Learning》要点整理与代码实现之二
    《Fast Traking via Spatio-Temporal Context Learning》要点整理与代码实现之一
    目录文件管理
    账号管理
    磁盘文件
  • 原文地址:https://www.cnblogs.com/AaronYang/p/4188663.html
Copyright © 2011-2022 走看看