Как правильно вернуть T из универсального метода при реализации интерфейса?

2

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

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 не будет работать, потому что тогда Бар не будет влиять на IFoo.

Теги:
generics
polymorphism

5 ответов

5
Лучший ответ

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

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

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

  • 0
    Хм, я пытаюсь проверить это сейчас, что я думаю, что я мог бы в конечном итоге сделать в CallOutputType - ((IFoo <T>) t) .OutputType (t); Я не могу изменить константу метода по другим причинам.
  • 0
    Спасибо за указание мне в правильном направлении, используя интерфейс для вызова метода работает.
0

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

0

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

Если вы добавите 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

Как добавить это в класс Bar:

    public override Foo OutputType(Foo param)
    {
        return this.OutputType((Bar)param);
    }
0

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню