【发布时间】:2021-07-03 15:03:11
【问题描述】:
给定一个通用的逆变接口:
public interface DoThis<in TParam> where TParam : Param
{
void Do(TParam param);
}
这有一个围绕Param的约束,一个标记接口:
public interface Param { }
存在具体实现的地方:
public class TheClass : DoThis<Concrete1>, DoThis<Concrete2>
{
public void Do(Concrete1 param) => Console.WriteLine("Called Concrete1");
public void Do(Concrete2 param) => Console.WriteLine("Called Concrete2");
}
Param 实现只是演示了这种情况:
public class Concrete1 : Param { }
public class Concrete2 : Param { }
public class Concrete3 : Param { }
问题
是否可以构建参数列表并测试该类是否实现特定接口并调用它,最好不进行反射?
是否可以让Non-reflective way using ref - call in a loop 在下面工作?
TheClass c = new TheClass();
Param[] @params = {new Concrete1(), new Concrete2(), new Concrete3()};
foreach (var p in @params)
{
c.Do(p);
}
以上当然不会编译。
反光解决方案
我们可以看看 [reflection] 来做到这一点...
foreach (var p in @params)
{
MethodInfo? method = c.GetType()
.GetMethods()
.FirstOrDefault(
x => x.Name == nameof(DoThis<Param>.Do)
&& x.GetParameters().Length == 1
&& x.GetParameters()[0].ParameterType == p.GetType());
method?.Invoke(c, new object[] {p});
}
控制台输出:
Called Concrete1
Called Concrete2
使用 ref 的非反射方式
这不太行。
private void DoParam<TParam>(TheClass c, TParam @event)
where TParam : Param
{
DoParam(ref c, ref @event);
}
private void DoParam<TParam>(ref TheClass c, ref TParam @event)
where TParam : Param
{
if (c is DoThis<TParam> projects)
{
projects.Do(@event);
}
}
循环调用
以下循环将 Param 作为类型传递,导致没有控制台输出:
foreach (var p in @params)
{
DoParam(c, p);
}
直接调用
但是,这会输出到控制台:
DoParam(c, new Concrete1());
DoParam(c, new Concrete2());
DoParam(c, new Concrete3());
输出:
Called Concrete1
Called Concrete2
【问题讨论】:
-
您让
TheClass负责为Param的每个单独子类提供Do的实现。那感觉不对。在Concrete1、Concrete2、Concrete3中实现Do怎么样?或者,如果您希望保持这些类干净,请引入具体参数类引用的单独类Doer1、Doer2、Doer3?如有必要,将(部分)TheClass注入这些新类或每个Do方法中。 -
@RuudHelderman - 我正在考虑对事件的预测。因此,该事件可以应用于读取模型或实体。我真的不想污染将应用它的事件 - 所以在这个问题中保持这个概念非常基本。