• C#积累(一)——扩展方法就近原则和匿名类型的成员探讨


    C#3.0多了扩展方法和匿名类型,今天探讨下这两个知识点一些容易忽视的地方

    项目:C# 控制台应用程序

    版本:.net 3.5

    运行IDE:VS 2008 SP1

    项目文件:Ext.cs、Anonymous.cs、Program.cs

    一,扩展方法就近原则

    首先要注意扩展方法可以扩展:类、接口、结构体

    其次扩展方法有就近原则,也就是如果在你的程序里有两个一模一样的扩展方法,一个和你的使用类是处于同一命名空间里,另外一个处于别的命名空间里,这个时候会优先使用同一命名空间里的扩展方法,也就是说“血缘关系”越近,越被青睐(此句为转摘)。

    那么在同一命名空间下在有同名扩展方法时是否会有就近原则呢?答案是No,会报错,请看:

    c#类库文件:Ext.cs

    代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace ExtAndVar
    {
        
    public class Ext
        {

        }

        
    static class ExtClassOne
        {
            
    public static void ExtOutPut(this Ext ext,string value)
            {
                Console.WriteLine(value);
            }
        }

        
    /*static class ExtClassTwo//如果这个类存在,调用ext.ExtOutPut("");会出现编译错误:在以下方法或属性之间的调用不明确:“ExtAndVar.ExtClassOne.ExtOutPut(ExtAndVar.Ext, string)”和“ExtAndVar.ExtClassTwo.ExtOutPut(ExtAndVar.Ext, string)”
        {
            public static void ExtOutPut(this Ext ext, string value)
            {
                Console.WriteLine(value);
            }
        }
    */
    }

    另外有个容易被忽视的知识点:扩展方法实现为静态方法,并使其至少具有与包含类相同的可见性。

    如果像下面这么写会报错:可访问性不一致: 参数类型“ExtAndVar.Ext”比方法“ExtAndVar.ExtClassOne.ExtOutPut(ExtAndVar.Ext, string)”的可访问性低

    代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace ExtAndVar
    {
        
    class Ext
        { 

        }

        
    public static class ExtClassOne
        {
            
    public static void ExtOutPut(this Ext ext, string value)
            {
                Console.WriteLine(value);
            }
        }

        
    /*static class ExtClassTwo//如果这个类存在,调用ext.ExtOutPut("");会出现编译错误:在以下方法或属性之间的调用不明确:“ExtAndVar.ExtClassOne.ExtOutPut(ExtAndVar.Ext, string)”和“ExtAndVar.ExtClassTwo.ExtOutPut(ExtAndVar.Ext, string)”
        {
            public static void ExtOutPut(this Ext ext, string value)
            {
                Console.WriteLine(value);
            }
        }
    */
    }

     言下之意就是被扩展类Ext的访问性不能比ExtClassOne低也不能比ExtOutPut低,这么做是为了保证能访问到ExtClassOne.ExtOutPut的地方也能访问到Ext

    二、匿名类型成员允许的类型

    匿名类型的成员都是公共只读属性,所以只要属性支持的成员就可以作为匿名类型的成员

    以下是MSDN的原话:匿名类型是由一个或多个公共只读属性组成的类型。不允许包含其他种类的类成员(如方法或显式事件)。

    下面这个例子我总结了下匿名类型支持的成员,以及隐式类型var的一些问题:

    c#类库文件:Anonymous.cs

    代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace ExtAndVar
    {
        
    class Anonymous
        {
            
    public delegate void TestHandler();
            
    public static event TestHandler et;
            
    public static event TestHandler ett
            {
                add
                {

                }
                remove
                {

                }
            }

            
    public static void Handler()
            {
                Console.WriteLine(
    "Call Handler!");
            }

            
    public static void TestOne()
            {
                var t 
    = new StringBuilder();
                t.Append(
    "看到没?var引用完全可以调用被引用对象的成员");

                
    object obj = new StringBuilder();
                
    //obj是object的引用,只能调用object表现出来的成员

                Console.WriteLine(t 
    is object);//输出True,因为t引用StringBuilder,StringBuilder继承object
            }

            
    public static void TestTwo()
            {
                var t 
    = new {i=3};
                
    //t.i = 4;这句会编译错误,记住匿名类型内的成员都是公共只读属性!

                var r 
    = new {s=new StringBuilder() };//匿名类型的成员可以是任何C#属性支持的成员
                r.s.Append("");
            }

            
    public static void TestThree()
            {
                TestHandler th 
    = Handler;
                var t 
    = new {th};//这表明匿名类型成员可以是委托实例
                t.th();
            }

            
    public static void TestFour()
            {
                et 
    += Handler;
                var t 
    = new { et };//这表明匿名类型成员可以是隐式声明的事件(ps:因为隐式声明的事件就是一个委托实例)
                t.et();

                ett 
    += Handler;
                
    //var r = new { ett };//编译出错,匿名类型的成员不能是显式声明的事件(ps:因为显式声明的事件是一种特殊的C#属性,匿名类型成员不能是属性)
            }

            
    public static void TestFive()
            {
                var al 
    = new[] { new { a = 1 }, new { a = 2 }, new { a = 3 } };//请注意匿名类型数组在初始化的时候不能指定数组长度,例如new[3] { new { a = 1 }, new { a = 2 }, new { a = 3 } }编译会出错,因为指定了长度3
                
    //var bl = new[] { new { a = 1 }, new { a = 2 }, new { b = 3 } };//编译出错,说明匿名类型数组里面装的如果也是匿名类型,要求所装的匿名类型是同一个类型(即匿名类型结构相同)
                int count = al.Length;
            }

            
    public static void TestSix()
            {
                var t 
    = new {i=3 };
                
    //var r = new {int i=3 };//编译出错,匿名类型成员不需要指定类型,匿名类型成员的类型会从赋值中推断出来
            }

            
    public static object TestSeven()
            {
                var t 
    = 1;
                
    return t;//可以用object返回var类型
            }

            
    public static int TestEight()
            {
                var t 
    = 1;
                
    return t;//也可以返回var实际引用的类型
            }
        }
    }

    最后是一个CLR启动文件,用于调用上面两个测试:

    Program.cs:

    代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace ExtAndVar
    {
        
    class Program
        {

            
    static void ExtInvoke()
            {
                Console.WriteLine(
    "------Ext------");
                Ext ext 
    = new Ext();
                ext.ExtOutPut(
    "Test");

                Console.WriteLine(
    "\n");
            }

            
    static void AnonymousInvoke()
            {
                Console.WriteLine(
    "------Anonymous------");
                Anonymous.TestOne();
                Anonymous.TestThree();
                Anonymous.TestFour();

                Console.WriteLine(Anonymous.TestSeven());
                Console.WriteLine(Anonymous.TestEight());
            }

            
    static void Main(string[] args)
            {
                ExtInvoke();
                AnonymousInvoke();
            }
        }
    }
  • 相关阅读:
    OO第四单元总结
    OO第三单元总结
    OO第二单元总结
    OO第一单元总结
    面向对象第四单元总结
    面向对象第三单元总结
    面向对象第二单元的总结
    操作系统lab3实验总结
    操作系统lab2实验总结——Part2
    操作系统lab2实验总结——Part1
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/1642693.html
Copyright © 2020-2023  润新知