接着上一篇《C#总结之泛型》,来继续总结C#语法,这篇主要汇总C#高级语法的用法,包括特性,初始化器,推理类型,匿名类型,动态查找,以及Lambda表达式,扩展方法,反射等用法。
特性可以为代码标记一些可以被外部读取的信息,通过这种方式来影响我们所定义类型的使用方式。
// 应用的目标类型:类,属性,或者其他,是否对同一个目标进行多次应用 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] class DoesInterestingThingsAttribute : Attribute { public int HowManyTimes { get; private set; } public string WhatDoesItDo { get; set; } public DoesInterestingThingsAttribute(int howManyTimes) { HowManyTimes = howManyTimes; } } [DoesInterestingThings(1000,WhatDoesItDo ="dahlin")] public class DecoratedClass {} static void Main(string[] args) { Type classType = typeof(DecoratedClass); object[] customAttributes = classType.GetCustomAttributes(true); foreach(object customAttribute in customAttributes) { WriteLine($"Attribute of type {customAttribute} found."); DoesInterestingThingsAttribute interestingThingsAttribute = customAttribute as DoesInterestingThingsAttribute; if (interestingThingsAttribute != null) { WriteLine($"This class does {interestingThingsAttribute.WhatDoesItDo} x {interestingThingsAttribute.HowManyTimes}"); } } ReadKey(); }动态查找功能由Dynamic Language Runtime,动态语言运行库,DLR支持。C# 4引入dynamic关键字,以用于定义变量。
class MyClass1 { public int Add(int var1, int var2) => var1 + var2; } class MyClass2 { } class Program { static int callCount = 0; static dynamic GetValue() { if (callCount++ == 0) { return new MyClass1(); } return new MyClass2(); } static void Main(string[] args) { try { dynamic firstResult = GetValue(); dynamic secondResult = GetValue(); WriteLine($"firstResult is:{firstResult.ToString()}"); WriteLine($"SecondResult is:{secondResult.ToString()}"); WriteLine($"firstResult call:{firstResult.Add(2,3)}"); WriteLine($"secondResult call:{secondResult.Add(2, 3)}"); } catch(RuntimeBinderException ex) { WriteLine(ex.Message); } ReadKey(); }Lambda表达式由3个部分组成,放在括号里的未类型化的参数,=>运算符,C#语句
表达式参数可以声明类型,如:(int paramA,int paramB)=>paramA+paramB 单个参数时省略括号,如:param1=param1*param2 没有参数时,()=>Math.PI;表达式语句体可以使用返回值:(a,b)=>{return value};Lambda表达式委托: Action,Action<>,Func<> 其中 Func<>中最后一个参数始终是返回值类型 delegate int TwoIntegerOperationDelegate(int paramA, int paramB); class Program { /// <summary> /// 主入口函数 /// </summary> /// <param name="args"></param> static void Main(string[] args) { WriteLine("f(a,b)=a+b"); PerformOperations((a, b) => a + b); WriteLine("f(a,b)=a*b"); PerformOperations((a, b) => a * b); WriteLine("f(a,b)=(a-b)%b"); PerformOperations((a, b) => (a-b)%b); ReadKey(); } static void PerformOperations(TwoIntegerOperationDelegate del) { for(int paramAVal = 1; paramAVal <= 5; paramAVal++) { for(int paramBVal = 1; paramBVal <= 5; paramBVal++) { int delegateCallResult = del(paramAVal, paramBVal); Write($"f({paramAVal},{paramBVal})={delegateCallResult}"); if (paramBVal != 5) { Write(","); } } WriteLine(); } }扩展方法被定义为静态方法,但它们是通过实例方法语法进行调用的。 它们的第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀。 扩展方法当然不能破坏面向对象封装的概念,所以只能是访问所扩展类的public成员。 扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用。 C#扩展方法第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀。 扩展方法的目的就是为一个现有类型添加一个方法,现有类型既可以是int,string等数据类型,也可以是自定义的数据类型。
static void Main(string[] args) { string strTest = null; // 调用扩展方法 var strResult = strTest.GetNotNullStr(); WriteLine(strResult); Person person = new Person(); person.Age = 20; // 调用自定义类的扩展方法 var isChild = person.GetBIsChild(); WriteLine(isChild); ReadKey(); } // 扩展方法 public static class MyString { public static string GetNotNullStr(this string strRes) { if (strRes == null) return string.Empty; else return strRes; } } public class Person { public string Name { set; get; } public int Age { set; get; } } // 自定义类的扩展方法 public static class MyPerson { public static bool GetBIsChild(this Person oPerson) { if (oPerson.Age >= 18) return false; else return true; } }注意事项:
(1)扩展方法不能和调用的方法放到同一个类中(2)第一个参数必须要,并且必须是this,这是扩展方法的标识 如果方法里面还要传入其他参数,可以在后面追加参数(3)扩展方法所在的类必须是静态类(4)最好保证扩展方法和调用方法在同一个命名空间下Reflection,中文翻译为反射。这是.Net中获取运行时类型信息的方式,.Net的应用程序由几个部分:程序集(Assembly)、模块(Module)、类型(class)组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息,例如:
Assembly类可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。Type类可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。MethodInfo包含方法的信息,通过这个类可以得到方法的名称、参数、返回值等,并且可以调用之。诸如此类,还有FieldInfo、EventInfo等等,这些类都包含在System.Reflection命名空间下。