c# - 仅当在 C# 中实现时才在接口实现上调用泛型方法
问题描述
给定一个通用的逆变接口:
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);
}
当然上面不会编译。
反光解决方案
我们可以看看 [反射] 来做到这一点......
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 c = new TheClass();
Param[] @params = { new Concrete1(), new Concrete2(), new Concrete3() };
foreach (var p in @params)
{
if (p is Concrete1 c1 && c is DoThis<Concrete1> t1) t1.Do(c1);
else if (p is Concrete2 c2 && c is DoThis<Concrete2> t2) t2.Do(c2);
else if (p is Concrete3 c3 && c is DoThis<Concrete3> t3) t3.Do(c3);
}
但是,我不建议这样做,因为当添加新的“具体”类时,必须一次又一次地手动扩展此代码。这很容易被遗忘。
推荐阅读
- python - 使用列列表更改多个数据框列数据类型
- android - 从android中的自定义布局访问按钮ID
- c++ - QImage.save 太慢了
- c# - 策略模式和两个存储库
- android - 无法使用普通 setImageUri 和 Picasso 在 ImageView 上设置图像 - Android Nougat
- qt - 构建 libQGLViewer 错误:找不到 lqglviewer-qt5
- regex - 使用正则表达式从浮点数中去除尾随零
- asp.net - 为什么在使用 POST 重定向到页面时必须使用表单
- node.js - 我的本地主机登录页面上的 POST 请求给出了 ERR_EMPTY_RESPONSE
- ios - AccessibilityTraits StartsMedia 不起作用