设为首页 加入收藏

TOP

【C#基础】我与接口二三事:扩展方法(一)
2019-09-17 18:57:35 】 浏览:54
Tags:基础 我与 接口 二三 扩展 方法

  语言的设计,真的是挺有意思的。第一次看这个代码[1]时,旁人随口了一句“哇,好多实心句号”。

  当时马上一个想法是——怎么实现的?返回了对象,然后再调用方法?然后就放下了,后来发现,这个是真值得说一说的。

            var sim = new InputSimulator();
            sim.Keyboard
               .ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.VK_R)
               .Sleep(1000)
               .TextEntry("notepad")
               .Sleep(1000)
               .KeyPress(VirtualKeyCode.RETURN)
               .Sleep(1000)
               .TextEntry("These are your orders if you choose to accept them...")
               .TextEntry("This message will self destruct in 5 seconds.")
               .Sleep(5000)
               .ModifiedKeyStroke(VirtualKeyCode.MENU, VirtualKeyCode.SPACE)
               .KeyPress(VirtualKeyCode.DOWN)
               .KeyPress(VirtualKeyCode.RETURN);

 

1. 神奇的链接(chaining

1.1 拓展方法

  想了很久该怎么引入话题,或者这样说,像这种写法,

  if (str == null || str == “”)

  相信刚刚开始编程的时候都这样写过,而C#语言规则里面,告诉我们可以这样写:

  string.IsNullOrEmpty(str);

  后来,有一天,我很自然地就写成这样了str.IsNullOrEmpty,当然,IDE都没有弹出IsNullOrEmpty这个函数我就知道不对了。

 

  嗯,如果非要写成str.IsNullOrEmpty这样,大概会很麻烦。

  首先string类型就是seal,重写一个string类那就……

  可以写静态方法,但其实也不美观,因为还是要这样 IsNullOrEmpty_test(str), 那和string.IsNullOrEmpty(str);  是没有区别的。

  这个时候,故事终于来到——拓展方法(Extension Methods)。

 

  下个定义吧,好说话。

  拓展方法,就是把对象自己作为第一个传入参数的静态方法。(这个“对象自己”,需要在形参前加个 this 前缀)

没有规则总是会乱套的,拓展方法有些语法[2]:

l   必须在一个非嵌套的、非泛型的静态类中;

l   至少有一个参数(就是对象它自己);

l   第一个参数必须附加this关键字前缀;

l   第一个参数不能有其他任何修饰符(比如out或ref);

l   第一个参数的类型不能是指针类型。 

 

 

  那么string.IsNullOrEmpty(str);能怎么改?

    class Program
    {
        static void Main(string[] args)
        {
            string str = "";
            Console.WriteLine(str.IsNullOrEmpty()); 
        }
    }

    static class NullUtil
    {
        public static bool IsNullOrEmpty(this string text)
        {
            return string.IsNullOrEmpty(text);
        }
    }

 

  这样看来,可能会有一些疑问,编译器怎么决定要使用的拓展方法?怎么个“非请勿来”?

    首先,如果总是会检测一下是不是实例方法;

    如果不是,就会去查一个合适的拓展方法。它会检查当前的、引用的所有拓展方法。 

TIPS:为了决定是否使用一个拓展方法,编译器必须能区分拓展方法与某静态类中恰好具有合适签名的其他方法。为此,它会检查类和方法是否具有System.Runtime.CompilerServices.ExtensionAttribute这个特性(它是.NET3.5新增的)。

 

 

  顺带一提,前面提及的InputSimulator类确实这样实现的,思想上是一致的。

    public class KeyboardSimulator : IKeyboardSimulator
    {
        ...
        public IKeyboardSimulator KeyPress(VirtualKeyCode keyCode)
        {
            var inputList = new InputBuilder().AddKeyPress(keyCode).ToArray();
            SendSimulatedInput(inputList);
            return this;
        }
        ...
    }

 

 

1.2 Lambda筛选与链接

  LINQ里面.where().Select().OrderBy().等等的“点点点”,就是基于拓展方法的思路。

     var list = new List<string> { "a", "b", "c", "d", "a", "b", "c", "d", "a", "a" };
     list = list.Where(a => a.Equals("a")).Reverse().ToList();
     list.ForEach(a => Console.WriteLine(a));

 

  在Where()点击F12,见:

  publicstatic IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);

 

    public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
    {
      if (source == null)
        throw Error.ArgumentNull(nameof (source));
      if (predicate == null)
        throw Error.ArgumentNull(nameof (predicate));
      if (source is Enumerable.Iterato
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C#Split的用法,Split分割字符串 下一篇58VIP账号发贴器

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目