使用'this'作为通用参数,转换问题

时间:2009-09-20 21:40:06

标签: c# generics

这可能吗?当我编译时,我得到一个错误,即使用约束

,也无法将Component转换为TComponent
public interface IComponent<TKey, TComponent> where TComponent : IComponent<TKey, TComponent>
{
    TComponent Parent { get; }
    void Register(TKey key, TComponent component);
    void RegsiterWith(TKey key, TComponent component);
}

public class Component<TKey, TComponent> : IComponent<TKey, TComponent> where TComponent : IComponent<TKey, TComponent>
{
    private TComponent _parent;

    public void Register(TKey key, TComponent component)
    {
        component.RegsiterWith(key, this);
    }

    public void RegsiterWith(TKey key, TComponent component)
    {
        component.Register(key, this);
    }

    public TComponent Parent { get { return _parent; } }
}

2 个答案:

答案 0 :(得分:8)

失败的原因是因为TComponent实际上可能是IComponent<TKey, TComponent>的某些其他实现。仅仅因为Component实现了接口并不意味着没有别的可以:)

这方面的一个方法是更改​​界面:

public interface IComponent<TKey, TComponent> 
    where TComponent : IComponent<TKey, TComponent>
{
    TComponent Parent { get; }
    void Register(TKey key, IComponent<TKey, TComponent> component);
    void RegsiterWith(TKey key, IComponent<TKey, TComponent> component);
}

在你的情况下我是否可行,我不知道,但它肯定会避免类型问题。

另一个选择是投射this作为消费者的建议。这可能在执行时失败,但实际上除非你创建一个替代实现,否则它不会。这有点令人讨厌,在使用泛型时必须施放,但偶尔会发生。

编辑:这是一个如何出错的例子:

public class Other : IComponent<string, Other>
{
    // Implement interface
}

现在如果您创建Component<string, Other>会怎样?它满足约束条件但没有问题......但Component不是Other ...

现在你可以改变你的约束:

public class Component<TKey, TComponent> : IComponent<TKey, TComponent> 
    where TComponent : Component<TKey, TComponent>

即。约束TComponent Component而不是IComponent。但仍有问题:

public class FooComponent : Component<string, FooComponent> {}
public class BarComponent : Component<string, FooComponent> {}

在这里,您可能希望BarComponent拥有TComponent,但它有一个不同的组件。你到目前为止所显示的代码可能还可以,但这种怪癖可能会妨碍其他目标。值得考虑......

哦,如果你很高兴Component密封,那么改变的约束 就足够了(我想!)。

答案 1 :(得分:0)

演员如何:

public void Register(TKey key, TComponent component)
{
    component.RegsiterWith(key, (TComponent)this);
}