从非泛型基类调用泛型方法/委托

5

我觉得我没有从正确的角度看待这个问题,而且我没有想到其他的解决方案。

假设有这个通用类;

public abstract class Port<T>
{
    public delegate T PullDelegate();

    private PullDelegate pull;

    public Port(PullDelegate pull)
    {
        this.pull = pull;
    }

    public T Pull()
    {
        return pull();
    }
}

它用于定义图形节点编辑器中的“端口”。端口可以将对象/值从一个节点传输到另一个节点,但它们也需要是“类型安全”的,这意味着我不能将任何类型错误的端口插入到另一个端口中(至少不会没有一些转换)。

节点“拥有”一个端口并向其方法提供委托,因此当另一个节点“拉”取值时,端口仅调用它并返回适当的值。

当我尝试从非泛型集合中调用Pull()时,我的问题开始了。显然,我可以创建一个非泛型基本方法,但是然后Pull可能无法返回T,而需要返回object

此外,每个节点都有其端口的集合访问器,因此其他项可以获取它们。该集合必须是非泛型的,因为一个节点可以有多个不同类型的端口。

    public abstract Port[] Inputs { get; }
    public abstract Port[] Outputs { get; }
    public abstract Port[] Entries { get; }
    public abstract Port[] Exits { get; }

一旦非泛型类型开始发挥作用,所有泛型都将变得无法访问。如果只有Port<>[]存在就好了。
我感觉好像漏掉了什么...

1
你可以创建一个 IPort<out T> { T Pull(); },然后创建一个 IEnumerable<Port<object>> - Lee
@SriramSakthivel:我还不确定。我的第一个想法是做 Port<T> : Port。现在,我正在尝试Lee的建议,使用 IPort<object> - LightStriker
@SriramSakthivel:如果我错了,请纠正我,但访问者模式会假设我提前知道所有可能的T类型,对吗?如果有人实现一个新的Port<Potato>而我不知道,那么它就会出问题? - LightStriker
不知道你想要如何使用和打算用返回值做什么,很难对此发表评论。请更新你的问题并提供这些信息,这将有助于我回答你的问题。 - Sriram Sakthivel
@LightStriker - 数组是不变的,因此您必须使用协变集合类型,如 IEnumerable<IPort<object>>IReadOnlyCollection<IPort<object>>。如果您需要使集合可变,则无法使用此方法。 - Lee
显示剩余5条评论
1个回答

3
使 Port<T> 实现非泛型接口 IPort,使用显式实现。这样可以隐藏它不在API中显示,但仍然允许您调用泛型类中的方法。
public interface IPort
{
    object SomeAction(object data);
}

public class Port<T> : IPort
{
    //[.. all other methods ..]


    object IPort.SomeAction(object data)
    {
        var typedData = (T)data;
        //invoke our typed version.
        return SomeAction(data);
    }

    public T SomeAction(T data)
    {
         // ...
    }
}

如果我的问题只是传递一些东西,我就不会费心使用泛型了。我遇到的问题是从中获取一些东西。假设你的 SomeAction 返回 T - LightStriker
@LightStriker:从 IPort.SomeAction 返回对象,以及从 IPort<T>.SomeAction 返回 T(其中 IPort<T> 实现了 IPort),你觉得怎么样?我认为这就是 IEnumerable/IEnumerable<T> 中所做的。 - devstruck
@jgauffin 实际上,我按照Devstruck的建议使用了一个类似于List<T>中IEnumerable实现的IPort/IPort<T>。它有效果。 我只是注意到,在我目前的使用方式中,通用IPort<T>可能实际上并不需要,但我可能会保留它以防万一。谢谢。 - LightStriker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接