将代理转换为C#中的通用代理 [英] Casting a Delegate to a Generic delegate in 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 Control
s. 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 StyleDel
s). 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 StyleDel
s 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屋!