Как правильно вернуть T из универсального метода при реализации интерфейса? - PullRequest
2 голосов
/ 26 июня 2009

Я работаю через ошибку. При воссоздании ошибки для следующего примера я смог определить причину возникновения проблемы. Но я застрял для лучшего решения. Итак, с учетом следующей программы:

public interface IFoo<T> {
    T OutputType(T param);
}

class Foo : IFoo<Foo> {
    public virtual Foo OutputType(Foo param) {
        Console.WriteLine("foo");
        return param;
    }
}

class Bar : Foo, IFoo<Bar> {
    public virtual Bar OutputType(Bar param) {
        Console.WriteLine("bar");
        return param;    
    }
}

class Program {
    static void Main(string[] args) {
        Bar bar = new Bar();
        CallOutputType(bar);
        bar.OutputType(bar);
    }

    static void CallOutputType<T>(T t) where T : Foo {
        t.OutputType(t);
    }      
}

Я ожидал, что результат будет:

bar
bar

Но то, что я получаю, это:

foo
bar

Видя проблему, упрощенную следующим образом, очевидно, что Bar.OutputType не переопределяет Foo.OutputType . Каковы мои лучшие варианты для улучшения этого дизайна? Bar.OutputType не может переопределить Foo.OutputType , потому что подписи разные. Изменение подписи Bar.OutputType для соответствия Foo.OutputType не будет работать, потому что тогда Bar не будет влиять IFoo .

Ответы [ 5 ]

5 голосов
/ 26 июня 2009

Э-э, я не слишком знаком с этим, но разве не должно быть:

static void CallOutputType<T>(T t) where T : IFoo<T>
{
   t.OutputType(t);
}

Это сработало, когда я его скомпилировал.

0 голосов
/ 26 июня 2009

Я не уверен, чего вы хотите достичь в конце, но поможет ли это?

Если вы добавляете Generic к тому, что когда-либо реализует IFoo, тогда вы можете указать тип при создании производного объекта ...

public class Foo<TFoo> : IFoo<TFoo>
{

}

//Then you code would allow this...
//Again other then returning Bar both times I am not certain exactly what you are 
//wanting to accomplish But specifying the type at create will allow you to return Bar 
//even if you created a Foo or a Bar...

class Program {
    static void Main(string[] args) {
        Foo foo = new Foo<Bar>();
        CallOutputType(foo);
        foo.OutputType(foo);
    }

    static void CallOutputType<T>(T t) where T : Foo {
        t.OutputType(t);
    }      
}
0 голосов
/ 26 июня 2009

Я бы на втором месте со Спенсером - когда вашим общим ограничением является T: Foo, оно типизирует ваш Bar в Foo, и, очевидно, вы можете вызвать метод OutputType класса Foo.

0 голосов
/ 26 июня 2009

Как насчет преобразования определения интерфейса таким образом, чтобы тип param был объявлен как расширенный IFoo?

0 голосов
/ 26 июня 2009

Как насчет добавления этого в класс Bar:

    public override Foo OutputType(Foo param)
    {
        return this.OutputType((Bar)param);
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...