Comisión de notas de estudio de C #

Delegado y evento son conceptos únicos propuestos en C #. En pocas palabras, delegado es una mejor implementación de "puntero de función" en C #, y evento es una mejor implementación de "función de devolución de llamada" en C #.


Tipo de delegación y asignación

Se puede considerar que el delegado es similar al puntero de función, es un tipo de referencia y se refiere a la función. La función a la que hace referencia el delegado tiene un tipo determinado. Un tipo de delegado representa la firma de la función (el tipo de parámetro y el orden de la función), por lo que se puede considerar con seguridad de tipos, es decir, un tipo de delegado no puede hacer referencia a ningún tipo que es incompatible con ella; una instancia de delegado puede representar una función específica, así como un método de instancia o método estático de una determinada clase, por lo que el delegado puede entenderse como un paquete o referencia de una función.

1. Declaración de tipos de delegado y variables de delegado

El formato de declaración es el siguiente:

修饰符 delegate 返回类型 委托名 (参数列表);

La lista de parámetros formales especifica la firma del delegado y el tipo de resultado especifica el tipo de retorno del delegado.
Ejemplo:

public delegate double MyDelegate(double x);

Esto declara un tipo de delegado, llamado MyDelegatetipo, y la función a la que puede hacer referencia es así: toma un doubleparámetro y el tipo de retorno también lo es double.
Dado que el delegado es un tipo, generalmente es paralelo a classla declaración , así que no lo escriba classen la definición. (Si está escrito en el classinterior, se convierte en un tipo anidado).
Declarar una variable de un tipo delegado es lo mismo que declarar una variable ordinaria:

	委托类型名 委托变量名;

Tal como:

	MyDelegate d;

2. La instanciación del delegado

El método para crear una instancia de un delegado y crear una instancia de un delegado es el siguiente:

	new 委托类型名(方法名);

El nombre del método puede ser un nombre de método estático de una determinada clase o un nombre de método de instancia de una instancia de objeto. P.ej:

	MyDelegate d1 = new MyDelegate(System.Math.Sqrt);
	MyDelegate d2 = new MyDelegate(obj.MyMethod);

La firma y el tipo de valor de retorno del método aquí deben ser coherentes con los declarados por el tipo de delegado, es decir, el delegado es de tipo estricto y seguro para el tipo.

Abreviatura de asignación delegada (azúcar de sintaxis): en C # 2.0 y superior, se puede abreviar como:

	MyDelegate d1 = System.Math.Sqrt;
	MyDelegate d2 = obj.MyMethod;

3. Llamada de delegado

Una característica importante del delegado es que el delegado no necesita preocuparse por el tipo de objeto al que pertenece el método cuando llama a un método. Solo requiere que la firma del método proporcionado coincida con la firma del delegado.

En el ejemplo DelegateIntergral.cs, calcule la integral de la función matemática:

delegate double Fun (double x);
class DelegateIntegral 
{
    
    
	static void Main (string[] args) {
    
    
	Console.WriteLine ("Hello World!");

	Fun fun = new Fun (Math.Sin);
	double d = Integral (fun, 0, Math.PI / 2, 1e-4);
	Console.WriteLine (d);

	Fun fun1 = new Fun (Linear);
	double d1 = Integral (fun1, 0, 2, 1e-3);
	Console.WriteLine (d1);

	Rnd rnd = new Rnd ();
	double d2 = Integral (new Fun (rnd.Num), 0, 1, 1e-2);
	Console.WriteLine (d2);

	}

	public static double Linear (double a) {
    
    
		return a * 2 + 1;
	}

	public static double Integral (Fun f, double a, double b, double eps) {
    
       // 积分计算 
		int n, k;
		double fa, fb, h, t1, p, s, x, t = 0;

		fa = f (a);
		fb = f (b);

		// 迭代初值
		n = 1;
		h = b - a;
		t1 = h * (fa + fb) / 2.0;
		p = double.MaxValue;

		// 迭代计算
		while (p >= eps) {
    
    
			s = 0.0;
			for (int i = 0; i < n; i++) {
    
    
				x = a + (i + 0.5) * h;
				s += f (x);
			}
			t = (t1 + h * s) / 2.0;
			p = Math.Abs (t1 - t);
			t1 = t;
			n += n;
			h /= 2.0;
		}
		return t;
	}
}

class Rnd 
{
    
    
	Random r = new Random ();
	public double Num (double x) {
    
    
		return r.NextDouble ();
	}
}

4. Fusión encomendada (multidifusión)

Los delegados no son solo un contenedor para los punteros de función, el uso de delegados fusionables tiene funciones mucho mejores que los punteros de función en otros lenguajes.

La combinabilidad de delegados también se llama multidifusión. En pocas palabras, se pueden llamar múltiples funciones a la vez. El delegado combinado es en realidad un paquete de múltiples funciones, y la llamada a dicho delegado son en realidad todas las llamadas a cada función empaquetada. Muchas de estas funciones se denominan colectivamente lista de llamadas del delegado.

De hecho, el compilador traduce todos los delegados en System.MulticastDelegatesubclases y las llamadas a los delegados se traducen en Invoke()llamadas a métodos.

El resultado de la operación de suma y resta comisionada, si no contiene una función, el resultado es null. Al llamar a un delegado que es igual a null, se producirá una NullReferenceExceptionexcepción en tiempo de ejecución , por lo que antes de llamar a un delegado, se debe juzgar si lo es null.
Ejemplo de DelegateMulticast.csuso de delegación de multidifusión:

delegate void D(int x);
class DelegateMulticast
{
    
    
	static void Main(string[] args) {
    
    
		Console.WriteLine("Hello World!");
		DelegateMulticast.Test();
	}
	public static void M1(int i) {
    
    
		Console.WriteLine("DelegateMulticast.M1: " + i);
	}
	public static void M2(int i) {
    
    
		Console.WriteLine("DelegateMulticast.M2: " + i);
	}
	public void M3(int i) {
    
    
		Console.WriteLine("DelegateMulticast.M3: " + i);
	}

	public static void Test() {
    
    
		D cd1 = new D(DelegateMulticast.M1);
		cd1(-1);		// call M1

		D cd2 = new D(DelegateMulticast.M2);
		cd2(-2);		// call M2

		D cd3 = cd1 + cd2;
		cd3(10);		// call M1 then M2

		cd3 += cd1;
		cd3(20);		// call M1, M2, then M1

		DelegateMulticast d = new DelegateMulticast();
		D cd4 = new D(d.M3);
		cd3 += cd4;
		cd3(30);		// call M1, M2, M1, then M3

		cd3 -= cd1;		// remove last M1
		cd3(40);		// call M1, M2, then M3

		cd3 -= cd4;
		cd3(50);		// call M1 then M2

		cd3 -= cd2;
		cd3(60);		// call M1

		cd3 -= cd2;		// impossible removal is benign
		cd3(60);		// call M1

		Console.WriteLine(cd3 == null);    // False
		cd3 -= cd1;		// invocation list is empty
		Console.WriteLine(cd3 == null);    // True

		//cd3 (70);		// System.NullReferenceException thrown

		cd3 -= cd1;		// impossible removal
		Console.WriteLine(cd3 == null);    // True
	}
}

5. Conversión e igualdad por encargo

Cualquier tipo de delegado se System.MulticastDelegatederiva implícitamente de él. Se puede acceder a los System.MulticastDelegatemiembros de la clase mediante el acceso de miembros . Pero System.MulticastDelegateno es un tipo de delegado, es un tipo de clase. El tipo de delegado está sellado implícitamente, es decir, no puede derivarse del tipo de delegado.

Los tipos de delegado en C # son equivalentes en nombre, no estructuralmente equivalentes. En otras palabras, dos tipos de delegado con diferentes nombres, incluso si tienen la misma firma y el mismo tipo de devolución, todavía se consideran tipos de delegado diferentes. Tal como:

delegate void D(int a);
delegate void E(int a);

Entonces D y E son dos tipos diferentes de delegados y no se pueden convertir entre sí.

Para dos instancias delegadas , el operador de igualdad ( ==) tiene un significado especial. Esto se debe a que cada tipo de delegado proporciona implícitamente operadores de comparación predefinidos. Dos instancias de delegado se consideran iguales en las siguientes situaciones:

  • Ambos son nullo son referencias a la misma instancia de delegado.
  • Si solo hay un método en el delegado, apuntan al mismo método estático o al mismo método de instancia del mismo objeto.
  • Si solo hay varios métodos en el delegado, el número de métodos es el mismo, los métodos correspondientes son los mismos y el orden es el mismo.

Según la definición anterior, diferentes tipos de comisiones también pueden ser iguales.
Ejemplo DelegateEqual.cs determina si dos delegados son iguales:

delegate void D(int a);
delegate void E(int a);
class DelegateEqual
{
    
    
	public static void M(int a) {
    
     }
	public static void Test() {
    
    
		E e = new E(M);
		D d = new D(M);
		e += e;
		d += d;
		//e = (E)d;		// 编译错误
		//d += e;

		Console.WriteLine(d.Equals(e));
		//Console.WriteLine(d == e);      // why??? 编译错误?
		Console.WriteLine(d);
	}
}

Supongo que te gusta

Origin blog.csdn.net/qq_45349225/article/details/114045717
Recomendado
Clasificación