将代理转换为C#中的通用代理 [英] Casting a Delegate to a Generic delegate in C#

查看:142
本文介绍了将代理转换为C#中的通用代理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简介



我正在使用委托人传递并存储个人表单 Control 的样式逻辑。例如,我有一个委托包含一些 Button -styling逻辑,如下所示:

  button.BackColor = Color.Red; 
button.ForeColor = Color.White;
button.FlatStyle = FlatStyle.Flat;

当然还有许多不同的其他类型的控件,如标签,面板等。所有这些代理我使用字典< Type,Delegate>



尽管委托本身如下所示:

  delegate void StyleDel< in T>(T control)其中T:Control; 

所以为了使用字典内的逻辑, Delegate 必须被转换为 StyleDel< T> 首先 - 任何 T 可能在那一刻。 / p>




情况



所有样式初始化后,存储,必须应用样式(使用 StyleDel s)。为此,我做了一个函数 StyleControl(control)



此函数查看控件的类型(例如 Button ),并找到相应的<$ c $从字典中的C> StyleDel ,这反过来应用( Button - )

  public void StyleControl&T;(T control)其中T:Control 
{
委托storedDel;
if(_dict.TryGetValue(control.GetType(),out storedDel))
{
//将代理转换为StyleDel
var styleDel =(StyleDel< T>)storedDel;

//执行StyleDel
styleDel(control);
}
}

StyleDel 被添加到字典中,添加函数如下:

  public bool Add< T>(StyleDel< T> styleDel)其中T:Control 
{
var inDict = _dict.ContainsKey(typeof(T));
if(!inDict)_dict [typeof(T)] = styleDel;
return!inDict;
}

StyleControl 函数被另一个函数调用,这样可以确保一切都是递归的样式:

  public void Style< T>(T parent)where T:Control 
{
StyleControl(parent);

//这个问题可能与这个
foreach有关(Control.Controls中的Control child)Style(child);
}






问题



一个 InvalidCastException 被抛出,说一个 StyleDel< Button> 不能被转换为 StyleDel< Control> 。所以我相信这个说法是 T 在这一点上被视为一个 Control ,而实际上它是一个按钮



如何将这个委托转换为 StyleDel< Button> 成功?

解决方案

你可以通过添加一个级别来实现这一点;创建一个调用您的委托的参数,将该参数转换为正确的类型:

 字典< Type,StyleDel< Control>> _dict = ... 

public bool Add< T>(StyleDel&T; styleDel)其中T:Control
{
var inDict = _dict.ContainsKey(typeof(T) );
if(!inDict)_dict [typeof(T)] = d => StyleDel((T)d);
return inDict;
}

乍看起来,这可能看起来不是安全的,但在这个特定的这是因为代理存储在具有参数的真实类型的字典中,因为它是关键。因此,预期使用将始终确保代理始终以正确类型的参数调用,并且不会发生运行时转换异常。


Introduction

I'm using delegates to pass along and store styling logic for individual form Controls. For example, I have a delegate containing some Button-styling logic like this:

button.BackColor = Color.Red;
button.ForeColor = Color.White;
button.FlatStyle = FlatStyle.Flat;

Of course there are many different other type of controls, like Labels, Panels, etc. So to store all these delegates I use a Dictionary<Type, Delegate>.

Although, the delegate itself looks like this:

delegate void StyleDel<in T>(T control) where T : Control;

So in order to use the logic inside the dictionary, the Delegate must be cast to StyleDel<T> first - whatever T might be at that moment.


The situation

After all of the styling is initialised and stored, the styling must be applied (using the StyleDels). For this I made a function StyleControl(control).

This function looks at the type of the control (e.g. a Button) and finds the corresponding StyleDel from the Dictionary, which in its turn applies the (Button-)styling.

public void StyleControl<T>(T control) where T : Control
{
    Delegate storedDel;
    if (_dict.TryGetValue(control.GetType(), out storedDel))
    {
        // Cast Delegate to StyleDel
        var styleDel = (StyleDel<T>) storedDel;

        // Execute StyleDel
        styleDel(control);
    }
}

The StyleDels are added to the dictionary with the Add function below:

public bool Add<T>(StyleDel<T> styleDel) where T : Control
{
    var inDict = _dict.ContainsKey(typeof(T)); 
    if (!inDict) _dict[typeof(T)] = styleDel;
    return !inDict;
}

And the StyleControl function is called by another function, which makes sure everything is styled recursively:

public void Style<T>(T parent) where T : Control
{
    StyleControl(parent);

    // The problem might have to do with this
    foreach (Control child in parent.Controls) Style(child);
}


The problem

An InvalidCastException is thrown, saying a StyleDel<Button> cannot be converted to StyleDel<Control>. So I believe it's saying that T is seen as a Control at this point, while it's actually a Button.

How do I cast this Delegate to a StyleDel<Button> successfully?

解决方案

You can achieve this by adding a level of inderection; create a lambda that calls your delegate casting the argument to the right type:

Dictionary<Type, StyleDel<Control>> _dict = ...

public bool Add<T>(StyleDel<T> styleDel) where T : Control
{
    var inDict = _dict.ContainsKey(typeof(T)); 
    if (!inDict) _dict[typeof(T)] = d => StyleDel((T)d);
    return inDict;
}

At first glance this might seem to not be type safe, but in this particular case it will be because the delegate is stored in a dictionary with the argument's true type as it's key. Intended usage will therefore always ensure that the delegate is always called with a correctly typed argument and a runtime cast exception will not happen.

这篇关于将代理转换为C#中的通用代理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆