• C#-LINQ


    隐式类型

     C#3.0。.NET Fraemork3.5出来的。

    编译器自动推算出来类型,语法糖。

    #region 隐式类型
    var a = 1;
    var b = "1";
    var c = 1.23m;
    var d = 1.23;
    Console.WriteLine(a.GetType());
    Console.WriteLine(b.GetType());
    Console.WriteLine(c.GetType());
    Console.WriteLine(d.GetType());
    #endregion
    View Code

    关键字var,编译的时候会根据右边的类型判断左边变量的具体类型。

    注意:是编译为中间语言的时候确定的。不影响性能。

    匿名类型
    #region 匿名类型
    string Name = "藏锋";
    //字段名字,Name根据上面定义的Name起名的。ID是自己定义的名字。
    var user = new { Name, ID = 1 };
    Console.WriteLine(user.Name);
    Console.WriteLine(user.ID);
    #endregion
    View Code

    不用实现写一个类,也可以创建一个对象,并且访问他的成员。

    注意:成员名字可以自己定义。  也可以把其他成员放进来(默认名字和其他成员一样,也可以自己在指定)

    自动属性
    #region 自动属性   属性不能定义在方法里面
    int _UserId;
    public int UserID
    {
        get { return _UserId; }
        set { _UserId = value; }
    }
    //自动属性,生成的中间语言和  先定义一个私有变量,在写他的访问器一样。
    public string UserNmae { get; set; }
    #endregion
    View Code

    自动属性在编译的时候生成他对应的私有字段。和get ,set方法。

    初始化器
    #region 初始化
    var stuInit = new Student() { Name = "藏锋", ID = 1 };
    IList<int> listInt = new List<int>() { 1, 2, 3, 4 };
    
    
    //无论是值类型还是引用类型使用的时候都要初始化 赋值。
    //值类型一般有默认值0
    //引用类型为NULL
    Student stuNULL;
    int intNULL;
    string strNULL;
    string refStr = string.Empty;
    int refID =0;
    Console.WriteLine(refStr);
    Console.WriteLine(refID);
    //传出参数使用的时候不需要赋值,原因在方法里面会给他赋值。
    string outStr;
    int outID;
    stuInit.GetUserName("WYX", ref refStr, ref refID, out outStr, out outID);
    #endregion
    View Code

    就是在对象创建的时候初始化他的一些值。

    委托
    #region 委托
    Student stuForDele = new Student();
    StuDele stuDele = new StuDele(stuForDele.GetUserId);
    stuDele += stuForDele.GetUserId1;
    stuDele += stuForDele.GetUserId2;
    stuDele += stuForDele.GetUserId3;
    stuDele -= stuForDele.GetUserId3;
    Console.WriteLine(stuDele(2));
    #endregion
    View Code

    委托是一个类型,和CLASS是一个级别的。

    泛型

     泛型类,泛型方法,泛型委托

    #region 泛型
    DAO<Teacher> dao = new DAO<Teacher>();
    Teacher teac = new Teacher();
    var pros1 = dao.GetAllPro();
    var pros2 = dao.GetAllPro(teac);
    Student stRef = new Student();
    var typeName = dao.GetTypeName<Student>(stRef);
    foreach (var item in pros1)
    {
        Console.WriteLine(item);
    }
    foreach (var item in pros2)
    {
        Console.WriteLine(item);
    }
    Console.WriteLine(typeName);
    #endregion
    泛型代码-代码过多只有一部分调用。源码页面下面下载

    面试经常问的,泛型特点:1,类型安全。2,节约装箱拆箱操作,性能比较好。3,代码重用扩展性强。4,可读性强

    1类型安全:用的是定义好的类型,不用object

    2性能高:比如说原来一个方法要根据参数做不同的事,参数类型还不一样。那么就只能把参数设置为object,这样就要装箱拆箱操作了。

    3代码重用:新建的类型只要符合泛型约束就可以用泛型的方法。

    原理:泛型每次编译的时候都会都会生成一套对应的类方法。和在程序里面一个一个写方法一样的。

    默认值:通过default关键字,将null赋予引用类型,将0赋予值类型。不能直接给泛型赋NULL或者0,因为不知道他是什么类型。

    泛型委托

    .NET框架自带三个系统泛型委托

    1、public delegate bool Predicate<in T>(T obj);

    //
    // 摘要:
    //     表示定义一组条件并确定指定对象是否符合这些条件的方法。
    //
    // 参数:
    //   obj:
    //     要按照由此委托表示的方法中定义的条件进行比较的对象。
    //
    // 类型参数:
    //   T:
    //     要比较的对象的类型。此类型参数是逆变。即可以使用指定的类型或派生程度更低的类型。有关协变和逆变的更多信息,请参见泛型中的协变和逆变。
    //
    // 返回结果:
    //     如果 obj 符合由此委托表示的方法中定义的条件,则为 true;否则为 false。
    注释  in逆变(传入参数)  out协变(传出参数)

     一个传入参数,返回类型为bool

    2、public delegate void Action<in T>(T obj);

    //
    // 摘要:
    //     封装一个方法,该方法只有一个参数并且不返回值。
    //
    // 参数:
    //   obj:
    //     此委托封装的方法的参数。
    //
    // 类型参数:
    //   T:
    //     此委托封装的方法的参数类型。此类型参数是逆变。即可以使用指定的类型或派生程度更低的类型。有关协变和逆变的更多信息,请参见泛型中的协变和逆变。
    注释

    没有返回值,0-16个传入参数

    3、public delegate TResult Func<out TResult>();

    //
    // 摘要:
    //     封装一个不具有参数但却返回 TResult 参数指定的类型值的方法。
    //
    // 类型参数:
    //   TResult:
    //     此委托封装的方法的返回值类型。此类型参数是协变。即可以使用指定的类型或派生程度更高的类型。有关协变和逆变的更多信息,请参见泛型中的协变和逆变。
    //
    // 返回结果:
    //     此委托封装的方法的返回值。
    注释

    最后一个参数为传出参数,一定有传出参数。前面0-16个传入参数。

    #region 泛型委托
    Student stupre = new Student() { ID = 10, Name = "WYX" };
    
    Predicate<int> pStu = new Predicate<int>(stupre.CheUsreID);
    Console.WriteLine(pStu(stupre.ID));
    
    //0-16个参数     17中方法重载
    Action ac1 = new Action(stupre.GetUserNameNoP);
    ac1();
    Action<string> ac2 = new Action<string>(stupre.GetUserNameNoP);
    ac2("123");
    
    //最后一个参数为返回参数out  协变   ,前面可以放0-16个参数
    Func<string> fun1 = new Func<string>(stupre.ToString);
    fun1();
    Func<int, int> fun2 = new Func<int, int>(stupre.GetUserId3);
    Console.WriteLine(fun2(5));
    #endregion
    三种框架泛型委托代码
    //自定义泛型委托
    NoInOutDele<int> custom1 = new NoInOutDele<int>(stupre.GetUserNameP);
    Console.WriteLine(custom1());
    OnePDele<string> custom2 = new OnePDele<string>(stupre.GetUserNameP);
    Console.WriteLine(custom2("藏锋"));
    OutPDele<string, string, string> custom3 = new OutPDele<string, string, string>(stupre.GetUserNameNoP);
    Console.WriteLine(custom3("123", "456"));
    自定义泛型委托
    匿名方法

       delegate(){}

    #region 匿名方法
    //委托里面添加的是一个个方法,可以写一个匿名方法给他   delegate(){} 
    //好处 可以访问上下文变量
    OutPDele<string, string, string> unNameFun1 = new OutPDele<string, string, string>(delegate (string s1, string s2)
    {
        return s1 + s2;
    });
    Console.WriteLine(unNameFun1("", ""));
    
    #endregion
    View Code

    语法糖,编译器会帮我们声明一个方法。(CLS中规定的是只有方法和字段)

    好处:可以访问上下文变量。

      什么代码可读性好,我感觉根据个人情况吧。编译到中间语言都一个样。

    注意:匿名方法不能复制给变量      var g = delegate (string s) { Console.WriteLine(s); }

    Lambda表达式

    匿名方法的更加简单写法。把匿名方法的delegate换成=>。编译器也会把他生成一个方法。

    无论是匿名方法还是Lambda表达式都是依赖于委托存在的。只有委托才调用他们。

    定义:表达者委托或表达式树的匿名方法。  本质是一个匿名方法,有时候这种代码看不懂得时候就想想他的本质,委托调用他们。

    #region Lambda
    OutPDele<string, string, string> lamdFun = new OutPDele<string, string, string>((string s1, string s2) =>
    {
        return s1 + s2;
    });
    //=>读 gos to
    //一个参数可以(string s)=>s或者s=>s
    //多个参数(string s1,string s2.....)  一定加括号
    //返回只有一条语句返回  s=>{return s;}  或者s=>s  (默认为返回)
    //多条语句  s=>{吧啦吧啦}
    OnePDele<string> lamdFun1 = new OnePDele<string>(s => { return s; });
    #endregion
    View Code
    //表达是一个委托
    OutPDele<string, string, string> lamdFunD = (string s1, string s2) => s1 + s2;
    lamdFunD.Invoke("1", "2");
    View Code

    Lambda表达式是一个匿名方法。语法:形参列表=>(goes to)方法体。“=>”运算符具有与“=”相同的优先级,并且是右结合性运算符。 
    一个参数可以(string s)=>s或者s=>s
    多个参数(string s1,string s2.....) 一定加括号
    返回只有一条语句返回 s=>{return s;} 或者s=>s (默认为返回)。去掉了大括号

    只有一条逻辑语句的例如   s=>{Console.WriteLine("1");}  或者s=>Console.WriteLine("1");  去掉了大括号
    多条语句 s=>{吧啦吧啦}

    Lambda表达式规则有三个

    1、 Lambda包含的参数数量必须与委托类型包含的参数数量相同。

    2、每个输入参数必须都能够隐式转换为其对应的委托参数。(逆变)

    3、返回值(如果有)必须能够够转换为委托的返回类型。(协变)

    扩展方法

    .net framork3.0

    目的:给一个类型增加行为

    结构:静态类(不能嵌套,泛型),静态方法,方法第一个参数为 (this  扩展的类型   调用这个扩展方法的对象 ),后面参数为扩展方法的参数。(this string var, string s1)                     (this string var, string s1, string s2)

    使用:在使用的类中添加他的命名空间,优先调用实例方法。  

    #region 扩展方法
    string s = "藏锋";
    Console.WriteLine(s.MargTwoStr("1", "2"));
    Console.WriteLine(s.MarMySelf("23"));
    #endregion
    View Code

    注意:

    Console.WriteLine(s.MarMySelf("23"));
    //上面和下面编译玩之后都一样的。只是上面的写的更友好。
    Console.WriteLine(StrExc.MarMySelf("1", "2"));

     THIS:四种用法

    1,当前类的实例

    public string GetUserNameNoP(string p_Name, string p_Name1)
    {
        return p_Name1 + this.Name + p_Name;
    }
    View Code

    2,串联构造函数

    调用一个构造函数的时候,他再去调用另外 一个构造函数this(若干构造函数参数)

    如果要构造基类的,就是base(若干构造函数参数)

    public Teacher()
    {
    
    }
    public Teacher(string p_TeacherName):this()
    {
    
    }
    public Teacher(string p_TeacherName, DateTime p_CreateDate) : base(p_CreateDate)
    {
    
    }
    View Code

    3,当前模块提到的扩展方法。

    4,索引器

    public class MyIndex
    {
        private string[] strList = new string[10];
        public string this[int index]
        {
            get { return strList[index]; }
            set { strList[index] = value; }
        }
    }
    
    public class MyIndexStr
    {
        //用string索引查看的药用hashtable  key value列表
        private Hashtable hash = new Hashtable();
        public string this[string indexstr]
        {
            set { hash.Add(indexstr, value); }
            get { return hash[indexstr].ToString(); }
        }
    }
    View Code

    讲一个面试经历:有一个公司在咖啡馆面试的(其实是一个小公司,没有办公地点),所有开发语言都招,去了先根据业务设计一个算法,在填写的英文简历,通过后才面谈,刚开始讲一大推讽刺的话,在讲来我们这里可以学到好多东西,(深深的套路呀)。然后开始问专业问题,中括号怎么用的,我说  索引器,他愣了一下(后来我猜他问的是JQ里面[]属性选择器,他做前端的,可能不懂后台),后面就开始嘲讽我,然后我怼了他两句走了。见到这种人不要怂,他们也是能忽悠到一个算一个。

      还有一次,他们公司开发三个人,每天加班到八点,周六也加班,然后说实行末位淘汰制,我想三个人你还淘汰啥。

    迭代器

    foreach的时候就是进行迭代操作,但是foreach遍历的集合必须继承IEnumerable接口实现了GetEnumerator方法(IEnumerable只有GetEnumerator()一个方法)。

    foreach数组的时候,其实编译器把foreach变成for了。

    迭代器的优点:对于一个较大的集合,不用一次性把数据全部加在出来。不需要遍历的时候一次加在一个。

    yield:在迭代器块中用于向枚举数对象提供值或发出迭代结束信号。(迭代器中用的就是这个东西,一次返回一个值

    #region 迭代器   都要继承IEnumerable接口实现了GetEnumerator方法。
    List<Teacher> teas = new List<Teacher>();
    for (int i = 0; i < 10; i++)
    {
        Teacher tae = new Teacher() { CreateUserID = i, TeacherName = i.ToString(), CreateDate = DateTime.Now };
        teas.Add(tae);
    }
    //我们foreach的时候就是使用的迭代器
    //但是数组也可以使用foreach,那是因为编译器把他转化为了for。中间语言中还是for
    //IEnumerable接口中只有一个方法。
    foreach (var item in teas)
    {
        Console.WriteLine(item.TeacherName);
    }
    foreach (var item in GetIterator())
    {
        Console.WriteLine(item.ToString());
    }
    //foreach遍历的集合每次只会返回一个,不把所有的都加载。GetIterator()方法一段一段的执行,遍历中间结束,后面的代码也不会执行
    
    foreach (var item in GetIterator())
    {
        if(item==2)
        {
            break;
        }
    }
    #endregion
    View Code
    //yield :在迭代器块中用于向枚举数对象提供值或发出迭代结束信号。
    static IEnumerable<int> GetIterator()
    {
        Console.WriteLine("迭代器返回了1");
        yield return 1;
        Console.WriteLine("迭代器返回了2");
        //终止迭代
        //yield break;
        yield return 2;
        Console.WriteLine("迭代器返回了3");
        yield return 3;
    }
    View Code

    注意事项:

    1:做foreach循环时多考虑线程安全性,在foreach时不要试图对被遍历的集合进行remove和add等操作任何集合,即使被标记为线程安全的,在foreach的时候,增加项和移除项的操作都会导致异常

    2:IEnumerable接口是LINQ特性的核心接口,只有实现了IEnumerable接口的集合,才能执行相关的LINQ操作,比如select,where等这些操作。

    LINQ

    前面都是准备知识,现在进入正题。

    分为两种模式

    1,查询操作符(扩展方法+lambda),扩展方法  扩展的事IEnumerable<T>接口。所以linq的基础都是集合要继承IEnumerable<T>。

    过滤:where,Find,FindAll,FindLast,First<T>,FirstOrDefault<>

    统计函数:Count,MIn,Sum,Max

    排序:OrderBy,OrderByDescending

    跳过前面多少条数据取余下的数据:SKIP

    从开始起获取指定数量的数据:TAKE

    模糊匹配:Contains

    分组:GroupBy        

    连接查询:Join

    投影:select(select t或者select(t=>new{t.1,t.2}))

    2,查询表达式

    From [type] id in source

    [join [type] id in source  on expr equals expr [into subGroup]]

    [from [type] id in source|let id=expr | where condition]

    [orderby ordering,ordering,ordering,ordering...]

    select select expr | group expr by key

    [into id query]

     tips:type是可选的,id是数据源集合中的一项,source是数据源集合,   其实是在一直循环source,每次循环把值放入select后面

    expr表示一个表达式,subGroup是一个临时变量,继承自IGroup,代表一个分组。

    可以有多个form,多个where,set指定临时变量

    可以有0-多个排序 orderby a descing orderby b。 orderby a descing ,b,c

    select  new投影(匿名类,返回的类型用var   因为他生成的时候一后台定义的类型集合),group 类型 by 具体属性。标准linq  前面一般写一个var(不确定类型)。              一个查询表达式必须以select或者group by结束。select后跟要检索的内容。group by 是对检索的内容进行分组

    group by 他后面只能跟 into is as 关键字,常用into 关键字放入临时数据源 然后在select 投影。

    into放入临时数据源

    Let 设置变量

    注意:这种查询表达式会编译成上面的扩展方法+lambad。这种是一个语法糖。

    源码下载

    推荐文章:http://www.cnblogs.com/liulun/archive/2013/02/26/2909985.html

    linqpad工具:http://www.linqpad.net/Download.aspx   (EF也可以用)(但是linq to sql,EF中都不建议使用linq,特别是复杂的查询。linqtosql貌似已经死了)

  • 相关阅读:
    ros学习之消息和服务
    linux软件安装
    ros使用QT插件开发
    使用客户端对象模型读取SharePoint列表数据
    使用服务器端对象模型,编写程序管理SharePoint列表
    Visual Studio创建简单的Event Receiver
    在SharePoint中使用LINQ
    使用Visual Stuidio 2010 创建网站列
    使用Visual Studio 创建新的Web Part项目
    在SharePoint页面嵌入简单的Silverlight程序
  • 原文地址:https://www.cnblogs.com/wudequn/p/6726435.html
Copyright © 2020-2023  润新知