首页 > 解决方案 > 泛型类型参数的 IEnumerable?

问题描述

我正在寻找一种方法来改进以下结构的代码:

foreach (var operation in operations)
{
    if (IsTypeAndDoSomething<Type1>(operation))
    {
        Run((Type1)operation);
    }
    else if (IsTypeAndDoSomething<Type2>(operation))
    {
        Run((Type2)operation);
    }
etc.

我宁愿避免一长串else if具有基本相同模式的块。

在这个项目中,我们创建了一个重载的 Run 方法来执行每个操作。当一个操作列表正在运行时,我们需要首先确定每个操作的类型,然后准备它(DoSomething 部分),然后再使用Run. 目前,如果方法似乎有必要,则重复 else 。

但是,我想知道 C# 中是否有任何方法可以使上面的代码更加“通用”而没有重复else if的 s。

一个想法是创建一个类型的集合,例如

我想知道是否有任何方法可以将类型列表迭代为泛型类型参数?

var types = new[] {typeof(Type1), typeof(Type1)};

然后,当我们添加一个新的操作实现时,我们可以简单地将它添加到该集合中(而不是多个else if块,我们将有另一个迭代器)。

但是,我们需要以某种方式将每个项目作为 Tx 传递:

IsTypeAndDoSomething<Tx>

似乎不可能在泛型类型参数 (T) 中引用这些类型。我认为这是因为它是在编译时而不是运行时完成的。

这是可能的还是推荐不同的模式?

标签: c#.net

解决方案


模式匹配的替代方法是使用访问者模式

你介绍一个访问者界面

interface IOperationsVisitor<T> {
    T Visit(Type1 obj);
    T Visit(Type2 obj);
}

并为您的操作添加一个 Accept 方法到基类:

T Accept(IOperationsVisitor<T> visitor) => visitor.Visit(this);

然后,您只需实现访问者接口并Accept在您的对象上调用该方法,并将访问者对象作为参数。

这比模式匹配要麻烦得多,但一个优点是,如果您引入新类型,您将被迫更新所有访问者以处理新类型。使用模式匹配很容易忘记检查类型的所有地方。


推荐阅读