Двухсторонняя ссылка с интерфейсами и обобщениями - PullRequest
1 голос
/ 02 ноября 2011

У меня есть класс с обобщениями, который использует другой класс, который в свою очередь должен знать, какой экземпляр исходного класса «владеет» им - что вызывает проблемы;) Позвольте мне привести пример:

public interface IFoo<T>
{
}

public interface IBar
{
    IFoo<IBar> Foo { get; set; }
}

public class Foo<T> : IFoo<T> where T : IBar, new()
{
    private readonly T _bar;
    public Foo()
    {
        _bar = new T {Foo = this};
    }
}

class Bar : IBar
{
    public IFoo<IBar> Foo { get; set; }
}

Это не работает, поскольку Foo = это не работает - даже если я пытаюсь привести это к IFoo (компилируется, но не работает во время выполнения).Я пытался настроить код различными способами, но я не нашел реализацию, которая работает ...

Надеюсь, вы видите, что я пытаюсь сделать, и, возможно, вы даже видите, как я могу достичьэто; -)

Ответы [ 2 ]

4 голосов
/ 02 ноября 2011

Это можно решить с помощью комбинации явного приведения в конструкторе вместе с поддержкой c # 4.0 для ковариации общих параметров.

Сначала вам нужно вставить приведение в конструктор Foo<T>:

_bar = new T {Foo = (IFoo<IBar>)this};

Просто делать этого недостаточно. Ваше ограничение, что T : new() означает, что T должен быть конкретным классом. Таким образом, IFoo<T> никогда не будет точно IFoo<IBar>. Однако если вы укажете, что универсальный параметр T для IBar<T> является ковариантным, то приведение от IFoo<Bar> к IFoo<IBar> станет допустимым:

public interface IFoo<out T>

Ключевое слово out указывает, что параметр является ковариантным (что, по сути, означает, что "этот параметр будет выводиться только методами, а не вводом.")

Эта статья MSDN предлагает более подробную информацию о ковариации и контравариантности.

2 голосов
/ 02 ноября 2011

Будет ли объявление параметра типа T IFoo ковариантным решить вашу проблему?
Этот код должен позволять вам делать то, что вы пытаетесь:

public interface IFoo<out T> {
}

public interface IBar {
    IFoo<IBar> Foo { get; set; }
}

public class Foo<T> : IFoo<T> where T : IBar, new() {
    private readonly T _bar;
    public Foo() {
        _bar = new T { Foo = (IFoo<IBar>)this };
    }
}

class Bar : IBar {
    public IFoo<IBar> Foo { get; set; }
}

public static class Program {

    public static void Main(params string[] args) {
        Bar b = new Bar();
        Foo<Bar> f = new Foo<Bar>();
    }

}
...