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

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

 

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

版本:.net 3.5

运行IDE:VS 2008 SP1

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

 

一,扩展方法就近原则

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

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

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

c#类库文件:Ext.cs

ExpandedBlockStart.gif 代码
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)”的可访问性低

ExpandedBlockStart.gif 代码
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

ExpandedBlockStart.gif 代码
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:

ExpandedBlockStart.gif 代码
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();
        }
    }
}

 

 

转载于:https://www.cnblogs.com/OpenCoder/archive/2010/01/09/1642693.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值