接口和泛型类约束之间的循环关系

时间:2018-03-06 22:22:14

标签: c# generics interface constraints

我似乎在思考这个问题。我不能在INameManageable中使用对父NameManager的引用(对象由NameManager拥有),因为它是通用的。

另一方面,如果我将INameManageable本身作为通用接口(即INameManageable< T>),我可以使用对NameManager的引用< T>在里面。但是后来我无法从同一个INameManageable派生所有可命名的类。

public interface INameManageable
{
    NameManager getParent(); // doesn't work because NameManager is generic!
    setParent(NameManager newParent);
    string getName(); // not relevant for the problem
    void setName(string name);
}

public class NameManager<T> where T: INameManageable
{
    readonly List<T> namedItems = new List<T>();

    public T Add(T item)
    {
        item.setParent(this);
        // ...
    }

    // ...
}

public class X: INameManageable
{
    // ...
}

public class Y: INameManageable
{
    // ...
}

public class ABunchOfNameManagers
{
    NameManager<X> anXNameManager;
    NameManager<Y> aYNameManager;
}

如何在此方案中建立对父级的引用?一旦我知道怎么做,我可能会自己面对...

1 个答案:

答案 0 :(得分:-1)

现在我明白了!这基本上是@JDDavis在他的(删除)答案中建议的内容。谢谢,伙计,我希望我能为此再次投票!很抱歉没有看到潜力。

关键是使界面也是通用的。

public interface INameManageable<T>
{
    NameManager<T> getParent();
    string getName();

    // derived class should use explicit interface implementation
    // so that no-one from external can fiddle with name or parent
    setParent(NameManager<T> newParent);
    void setName(string name);
}

public class NameManager<T> where T: class, INameManageable<T>
{
    readonly List<T> namedItems = new List<T>();

    public T Add(T item)
    {
        // ...
        namedItems.Add(item);
        item.setParent(this);
    }
}

public class X: INameManageable<X>
{
    // publicly accessible
    public NameManager<T> getParent() {/* ... */}
    public string getName() {/* ... */}

    // this is called "explicit interface implementation";
    // basically means "private", unless somebody explicitly
    // casts us to the interface (so it's at least discouraged)
    void INameManageable<T>.setName(string name) {/* ... */}
    void INameManageable<T>.setParent(NameManager<T> nameManager) {/* ... */}
}

public class Y: INameManageable<Y>
{
    // ... same here ...
}

public class ABunchOfNameManagers
{
    NameManager<X> anXNameManager;
    NameManager<Y> aYNameManager;
}

感谢大家的富有成效的讨论!

修改:我忘了同步我在此期间所做的更改。我怀疑这是导致@Servy批评类型安全的原因。无论如何,它适用于我的应用程序。