我们正在处理大量WinForms旧代码,并且正在缓慢地进行重构,分解依赖关系,实现MVP模式并将逻辑从窗体和用户控件移到演示者中。
我们已经添加了Castle Windsor,它创建了一个ViewFactory,该ViewFactory返回带有Presenter及其附加所有依赖项的窗体/用户控件。
几乎每个屏幕上都使用一个用户控件,我们已经对其进行了重构,但尚未完成所有使用它的屏幕的重构,因此其中一些正在使用ViewFactory,而某些仍在调用该控件的构造函数,课程不会创建演示者。
我可以解决的方法是检查控件现在具有的事件是否为null,如果是,则意味着没有演示者已订阅它们,因此我手动创建它。这可以工作,但是由于有一些事件可以在不同的时间触发,这意味着我必须执行以下操作:
private void RaiseEventForPresenter(ref EventHandler action, EventArgs e)
{
if(action == null) CreatePresenter();
action.Invoke(this, e);
}
private void RaiseEventForPresenter(ref CustomDelegate1 action, CustomDelegate1EventArgs e)
{
if(action == null) CreatePresenter();
action.Invoke(this, e);
}
private void RaiseEventForPresenter(ref CustomDelegate2 action, CustomeDelegate2EventArgs e)
{
if(action == null) CreatePresenter();
action.cInvoke(this, e);
}
private void CreatePresenter()
{
new Presenter(this, new Bl(new Dal(new ConnectionManager())));
}
请注意,在创建演示者并订阅了视图的事件后,需要将该委托作为ref传递,以便成功调用该委托。
我不想对每种事件使用不同的重载方法,而是要这样做:
private void RaiseEventForPresenter<T1, T2>(ref T1 action, T2 e)
{
if (action == null) CreatePresenter();
action.Invoke(this, e); //Does not compile
}
当然T1不包含 Invoke 方法的定义。到目前为止,我已经尝试过:
将动作投射到动作:
((Action<object, T2)action).Invoke(this, e);
将T1重新定义为代表:
private void RaiseEventForPresenter<T>(ref Delegate action, T e) ...
将T1重新定义为动作:
private void RaiseEventForPresenter<T>(ref Action<object, T> action, T e) ...
所有这些选项给我带来了不同的编译错误,所以我的问题是,这能完全实现吗?
答案 0 :(得分:1)
这个问题很难解决,因为generics won't allow a delegate as a type constraint,所以我们不能编写一个通用方法来接受任何特定类型的委托。
但是我们可以在委托内的类型参数内指定类型约束。因此,解决方案是摆脱CustomDelegate1
和CustomDelegate2
,而使用诸如CustomDelegate<T>
之类的通用版本,并将事件arg类型作为通用参数传递。
这是委托和事件参数定义的外观:
public class CustomEventArgs1 : EventArgs { }
public class CustomEventArgs2 : EventArgs { }
public delegate void CustomDelegate<T>(object sender, T e) where T : EventArgs;
这是您的方法:
public void RaiseEventForPresenter<T>(ref CustomDelegate<T> action, T args) where T : EventArgs
{
if (action == null) CreatePresenter();
action(this, args);
}