Я работаю над ошибкой. В воссоздании ошибки для следующего образца я смог определить, почему проблема происходит. Но я застрял для лучшего решения. Так, учитывая следующую программу:
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.
Э-э, я не слишком хорошо разбираюсь в этом, но не должен:
static void CallOutputType<T>(T t) where T : IFoo<T>
{
t.OutputType(t);
}
Это сработало, когда я скомпилировал его.
Как насчет преобразования определения интерфейса, чтобы объявить тип param
для расширения IFoo
?
Я не уверен, что именно вы хотите достичь в конце, но поможет ли это?
Если вы добавите 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);
}
}
Как добавить это в класс Bar:
public override Foo OutputType(Foo param)
{
return this.OutputType((Bar)param);
}
Я бы второй раз упомянул Spencer, когда у вас общее ограничение T: Foo, оно выводит ваш Bar в Foo, и, очевидно, вы получите вызов метода OutputType класса Foo.