c#学习笔记——7

来源:互联网 发布:ubuntu进不去登录界面 编辑:程序博客网 时间:2024/05/20 10:20
委托链:


委托链就是将多个方法加到一个委托变量上
使用+=将方法名加到委托变量上。
使用-=将方法移除。



当使用=时,之前追加的方法将清除
比如
Mydelegate += m1.f1;//这样写也可以
Mydelegate = Mydelegate+m2.f1;;
Mydelegate += m3.f1;
后面加Mydelegate=m4.f1;
则委托里面只有m4.f1;




例子:
namespace 复习
{
    public delegate void FuncDelegate(); 
    // 定义了一个名为FuncDelegate的委托类型
    class Program
    {
        static void Main(string[] args)
        {
            FuncDelegate MyFunc;


            MyFunc = Func1;
            MyFunc += Func2;
            MyFunc += Func3; 
            MyFunc += Func4;


            MyFunc();


            Console.ReadKey();
        }


        public static void Func1()
        {
            Console.WriteLine("Func1");
        }
        public static void Func2()
        {
            Console.WriteLine("Func2");
        }
        public static void Func3()
        {
            Console.WriteLine("Func3");
        }
        public static void Func4()
        {
            Console.WriteLine("Func4");
        }
    }
}
例子:委托链
namespace Test
{
    public delegate void delegatamachines();
    class Program
    {
        static void Main(string[] args)
        {
            Contriolroom c = new Contriolroom();
            c.Mydelegate();
            Console.ReadLine();


        }
    }
    class Machine1
    {
        public void f1()
        {
            Console.WriteLine("关闭机器1");
        }
    }
    class Machine2
    {
        public void f1()
        {
            Console.WriteLine("关闭机器2");
        }
    }
    class Machine3
    {
        public void f1()
        {
            Console.WriteLine("关闭机器3");
        }
    }
    class Contriolroom
    {
       public delegatamachines Mydelegate;
        Machine1 m1 = new Machine1();
        Machine2 m2 = new Machine2();
        Machine3 m3 = new Machine3();


        public Contriolroom()
        {
            Mydelegate = Mydelegate+m1.f1;
            Mydelegate = Mydelegate+m2.f1;
            Mydelegate += m3.f1;
            
        }




        public void Close()
        {


            Mydelegate();


        }


    }
}




委托本质
看起来委托变量调用方法是使用“委托名()”
但实际上是委托对象中的Invoke方法触发调用“注册”到委托变量的方法


在委托变量上调用GetInvocationList,返回一个Delegata数组




例子:
namespace 委托链的返回值
{
    public delegate int FuncDelegate();


    class Program
    {
        static void Main(string[] args)
        {
            FuncDelegate MyFunc;
            MyFunc = F1;
            MyFunc += F2;
            MyFunc += F3;
            MyFunc += F4;
            // 这样的调用方法没有办法得到返回值
            // 如果需要返回值,使用循环调用
            //int res = MyFunc();
            //Console.WriteLine();
            //Console.WriteLine(res);  //输出 F1   F2   F3   F4   4


            // 在委托变量上调用GetInvocationList方法,返回一个Delegate数组
            Delegate[] ds = MyFunc.GetInvocationList();
            for (int i = 0; i < ds.Length; i++)
            {
                int res = ((FuncDelegate)ds[i])();
                Console.WriteLine(res);
            }


            Console.ReadKey();
        }


        static int F1()
        {
            Console.WriteLine("F1");
            return 1;
        }
        static int F2()
        {
            Console.WriteLine("F2");
            return 2;
        }
        static int F3()
        {
            Console.WriteLine("F3");
            return 3;
        }
        static int F4()
        {
            Console.WriteLine("F4");
            return 4;
        }
    }
}






爷类:Delegate 
父类:MulticaselistDelegate
子类:自己定义的委托类型






如果要控制需要在外界添加方法,但是不让外界调用
声明一个私有委托,然后添加一个可以添加方法与移除方法的属性




事件本质  私有委托变量加Add Remove
委托于时间区别:
委托时类型,事件是对象
委托可以在外部任何地方被调用
事件不能
委托可以用=
事件只能用+=
事件用来阉割委托事例


订阅      为事件赋值的过程
订阅者    方法
发布      定义时间
委托在做系统开发时经常用到


委托于指针的区别
委托是类型安全的,面向对象的,有丰富的内部结构数据
指针式不安全的代码,面向过程的,是一个地址指向




匿名方法:
例子:
FuncDelegate Mydelegate=delegate()
{
  Console.WriteLine("哈哈");    
};


Lambda表达式:
//在Linq里面用的相对多
//括号参数可以不写类型
//可以随意的访问该方法中的变量
FuncDelegate Mydelegate=()=>
{
  Consolw.WriteLine("哈哈");
}


// 如果Lambda表达式只有一句话,花括号可省略
FuncDelegate MyFunc = (i) => Console.WriteLine(num);




类型推断:


int num = 123;
var v = "100";//var可以根据=右边的类型推断
var a;   a=10;//错误的写法。定义是就要赋值    
 使用类型推断必须是确定的诶性 
//Console.WriteLine(v); 


匿名类型
例子:


var person = new
{
 Name = "张三",
 Age = 19,
 Gender = '男'
};


Console.WriteLine(person.Name);
Console.ReadKey(); 




初始化器使用的例子:


int[] nums = new int[] { 1, 2, 3 };
List<int> numList = new List<int>() { 11, 22, 33, 44, 55, 66 };
Person p = new Person(){ Age=19, Gender='男', Name="张三"}; 












1.静态类
2.提供静态方法
3.所有参数一致,完成你想要做的事
4.将需要处理的类型前加上一个this
例子:


    static class MMM    //静态类
    { 
        public static bool IsEmail(this string s)  //注意这里加this    静态方法
        {
            if (Regex.IsMatch(s, @"^\w+@\w+(\.\w+)+$"))
            {
                return true;
            }
            else
            {
                return false;
            } 
        }
    }


然后字符串对象就能调用这个方法了。
例如:
string s="hahaha@hehehe.com";
if(s.IsEmail())
{
  ......
}




运算符重载:
本质是方法:


在Person类中定义如下代码:
public static int operator +(Person p1,Person p2)
{
  return p1.Age+p2.Age;
}


              explicit显示转换
public static implicit operator int(Person value)//隐式类型转换
{
return value.Age
}




XML:
常用的类
XDocument
XElement
XAttribure


XName
XNode


例子:
        static void Main(string[] args)
        {


            // 创建一个xml文档
            XDocument xDoc = new XDocument();
            // 添加根节点
            XElement xRoot = new XElement("Root");
            // 添加节点使用Add
            xDoc.Add(xRoot);


            // 创建一个学生加到root中
            // 1、创建学生节点
            XElement xStudent = new XElement("Student");
            // 2、创建学生姓名、年龄、相别
            XElement xName = new XElement("Name");
            XElement xAge = new XElement("Age");
            XElement xGender = new XElement("Gender");
            xName.Value = "张三";
            xAge.Value = "19";
            xGender.Value = "男";


            // 3、添加节点(没有顺序之分)
            xStudent.Add(xName, xAge, xGender);
            xRoot.Add(xStudent);


            // 为Student添加属性
            XAttribute xId = new XAttribute("id", "dotnet0001");
            xStudent.Add(xId);


            // 保存该文档
            xDoc.Save(@"G:\myxml.xml");
        }


序列化成XML
   class Program
    {
        static void Main(string[] args)
        {
            List<Person> perList = new List<Person>()
            {
                new Person(){ Name="张三1",Age=19, Gender='男'},
                new Person(){ Name="张三2",Age=19, Gender='男'},
                new Person(){ Name="张三3",Age=19, Gender='男'},
                new Person(){ Name="张三4",Age=19, Gender='男'},
                new Person(){ Name="张三5",Age=19, Gender='男'},
                new Person(){ Name="张三6",Age=19, Gender='男'},
                new Person(){ Name="张三7",Age=19, Gender='男'},
                new Person(){ Name="张三8",Age=19, Gender='男'},
                new Person(){ Name="张三9",Age=19, Gender='男'},
                new Person(){ Name="张三10",Age=19, Gender='男'},
                new Person(){ Name="张三11",Age=19, Gender='男'},
                new Person(){ Name="张三12",Age=19, Gender='男'}
            };


            using (FileStream file = 
                new FileStream("xml.xml", FileMode.Create, FileAccess.Write))
            {
                XmlSerializer ser = new XmlSerializer(typeof(List<Person>));
                ser.Serialize(file, perList);
            }
        }
    }


    [Serializable]
    public class Person
    {
        private string _name;


        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        private int _age;


        public int Age
        {
            get { return _age; }
            set { _age = value; }
        }
        private char _gender;


        public char Gender
        {
            get { return _gender; }
            set { _gender = value; }
        }


        public Person(int age, char gender, string name)
        {
            _name = name;
            _age = age;
            _gender = gender;
        }


        public Person()
        {
        }


    }




程序集:
.net生成的exe文件和dll文件都是程序集(还有一种dll叫动态链接库,不属于程序集)


程序集里有:
1.PE头
2.资源
3.元数据、IL代码


元数据相当于程序清单:比如 几个类、几个命名空间、类里面有字段、方法以及父类子类关系等。


JIT just in time 即时编译器




反射:反射就是读取程序集,得到对象,创建对象,使用对象
读取dll
创建对象
使用对象


Type 为 System.Reflection 功能的根,也是访问元数据的主要方式。
使用 Type 的成员获取关于类型声明的信息,如构造函数、方法、字段、属性和类的事件,以及在其中部署该类的模块和程序集。 (from MSDN)






创建对象,就需要获得对象的类型信息  使用typeof获得一个Type类型的
Type myType = typeof(Person);  


根据类型信息创建对象      使用Activator.CreateInstance() 创建对象实例
object o = Activator.CreateInstance(myType);


根据类型信息获得方法      
MethodInfo m = myType.GetMethod( "Func", new Type[] { typeof(int), typeof(string), typeof(char) } );  (有参数的方法)
MethodInfo m = myType.GetMethod( "Func", Type.EmptyTypes);                          (没有参数的方法)


调用实例的方法:
m.Invoke(o, new object[] { 100, "哈哈", '男' });   (有参数的)
m.Invoke(o, null);                                  (没有参数的)




步骤总结:
1.获得对象的Type类型type


2.通过type创建对象,通过type获得方法  


3. 调用实例的方法






读取dll:
加载程序集
Assembly asm = Assembly.LoadFile(全路径名);


通过读取程序集,得到对象
得到类型需要写全路径名
Type t = asm.GetType("ConsoleApplication2.Program");          Type type = assembly.GetType("程序集.类名");获取当前类的类型


2.通过type创建对象,通过type获得方法 
object o = Activator.CreateInstance(t);
MethodInfo mi = t.GetMethod("Func");
3. 调用实例的方法
mi.Invoke(o, null);






CC c = new CC();
bool isRight = typeof(IF).IsAssignableFrom(c.GetType());
// t.IsSubclassOf()不能用作接口的判断
/*
* 如果类型是通过接口派生的子类,那么为了实现调用,
* 可以判断读取的类型Type变量是否来源于该接口






public virtual bool IsAssignableFrom(
    Type c
)


如果满足下列任一条件,则为 true:
 c 和当前 Type 表示同一类型;
 当前 Type 位于 c 的继承层次结构中;
 当前 Type 是 c 实现的接口; 
 c 是泛型类型参数且当前 Type 表示 c 的约束之一。
 如果不满足上述任何一个条件或者 c 为 nullNothingnullptrnull 引用(在 Visual Basic 中为 Nothing),则为 false。 (from MSDN)




反射实例:计算器


定义一个接口,有一个Operation只读属性,和一个double Calculating()方法。




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


namespace MyInterface
{
    public interface ICalculatable
    {
        string Operation
        {
            get;
        }
        double Calculating();
    }
}


















定义一个工厂类,里面有一个Create(double num1, double num2, string oper)方法,返回一个ICalculatable类型的接口,实现统一调用。


每一个具体计算方法可以分别写在Method文件夹下不同的dll中,
下面例子将实现反射。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MyInterface;
using System.Reflection;
using System.IO;


namespace MyFactory
{
    public static class Facotory
    {
        public static ICalculatable Create(double num1, double num2, string oper)
        {
            ICalculatable temp = null;
            // 利用反射读取本地文件夹Method中的所有dll
            string source = Assembly.GetExecutingAssembly().Location;
            string path = Path.Combine(Path.GetDirectoryName(source), "Method");
            if (Directory.Exists(path))
            { 
                // 得到里面所有的dll
                string[] dlls = Directory.GetFiles(path, "*.dll");
                for (int i = 0; i < dlls.Length; i++)
                {
                    // 遍历加载各个dll
                    Assembly asm = Assembly.LoadFile(dlls[i]);
                    // 获得public的Type信息
                    Type[] types = asm.GetExportedTypes();
                    // 获得接口的type
                    Type tInterface = typeof(ICalculatable);
                    for (int j = 0; j < types.Length; j++)
                    {
                        Type t = types[j];
                        
                        if (!t.IsAbstract && tInterface.IsAssignableFrom(t))
                        {
                            // 创建实例
                            ICalculatable iTemp = (ICalculatable)Activator.CreateInstance(t, num1, num2);
                            
                            if (iTemp.Operation == oper)
                            {
                                temp = iTemp;
                                goto label;
                            }
                        }
                    }
                }
            }
            label:
            return temp;
        }
    }
}















原创粉丝点击