C# – Kontravarianz bei Delegaten

C# – Kontravarianz bei Delegaten

In diesem Artikel besprechen wir ein Szenario, in dem Sie die Vorteile der Kontravarianz nutzen können, um Delegierte zu verwenden


Problem:


In früheren Versionen von .NET gab es Situationen, in denen sich Delegaten nicht wie erwartet verhielten.

Beispielsweise sollte ein Delegat mit einem Typparameter einer Basisklasse Delegaten eines stärker abgeleiteten Typparameters zuweisbar sein, da jeder Delegat, der mit der Basisklasse aufrufbar ist, auch mit der abgeleiteten Klasse aufrufbar sein sollte. Das folgende Codebeispiel veranschaulicht das Problem:

Angesichts dieser Klassendefinitionen:

class Shape
{
public void Draw() { Console.WriteLine(“Drawing shape”); }
};

class Rectangle : Shape
{
public void Expand() { /*...*/ }
};

//And given this delegate and method:

delegate void ShapeAction< T>(T shape);
static void DrawShape(Shape shape)
{
if (shape != null)
{
shape.Draw();
}
}

Sie würden erwarten, dass dieses Szenario funktioniert:

ShapeAction<Shape> action = DrawShape;
ShapeAction<Rectangle> rectAction2 = action;

Schließlich kann DrawShape jede Art von Shape annehmen, einschließlich Rectangle. Leider hat dieses Szenario nicht wie erwartet funktioniert.

Lösung:


In .NET 4 wurde dies durch Kontravarianz bei Delegaten behoben, damit Sie weniger spezifische Delegate spezifischeren Delegaten zuweisen können, solange der Typparameter T als „in“ deklariert ist, was bedeutet, dass der Delegat nicht zurückkehrt T. Im folgenden Code wurde der Typparameter des Delegaten mit in.

class Shape
{
public void Draw() { Console.WriteLine("Drawing shape"); }
};

class Rectangle : Shape
{
public void Expand() { /*...*/ }
};

class Program
{
delegate void ShapeAction<in T>(T shape);
static void DrawShape(Shape shape)
{
if (shape != null)
{
shape.Draw();
}
}
static void Main(string[] args)
{}

//this should obviously be ok

ShapeAction<Shape> action = DrawShape;
action(new Rectangle());

/* Intuitively, you know any method that
* conforms to a ShapeAction<Shape> delegate
* should also work on a Rectangle because
* Rectangle is a type of Shape.
*
* It’s always possible to assign a less derived _method_
* to a more-derived delegate, but until .NET 4
* you could not assign a less-derived _delegate_ to
* a more-derived delegate: an important distinction.
*
* Now, as long as the type parameter is marked as “in”
* you can.
*/
//this was possible before .NET 4
ShapeAction<Rectangle> rectAction1 = DrawShape;
rectAction1(new Rectangle());

//this was NOT possible before .NET 4
ShapeAction<Rectangle> rectAction2 = action;
rectAction2(new Rectangle());
Console.ReadKey();
}
}
geändert

Vielen Dank für Ihren Besuch !!