【发布时间】:2019-01-24 19:32:40
【问题描述】:
最近我尝试了访问者模式的实现,我尝试使用通用接口强制执行 Accept & Visit 方法:
public interface IVisitable<out TVisitable> where TVisitable : IVisitable<TVisitable>
{
TResult Accept<TResult>(IVisitor<TResult, TVisitable> visitor);
}
- 其目的是 1)将某个类型“Foo”标记为此类访问者可访问,而访问者又是“此类 Foo 类型的访问者”,以及 2)在实现的可访问类型上强制执行正确签名的 Accept 方法,就像这样:
public class Foo : IVisitable<Foo>
{
public TResult Accept<TResult>(IVisitor<TResult, Foo> visitor) => visitor.Visit(this);
}
到目前为止一切顺利,访问者界面:
public interface IVisitor<out TResult, in TVisitable> where TVisitable : IVisitable<TVisitable>
{
TResult Visit(TVisitable visitable);
}
-应该 1) 将访问者标记为“能够访问”TVisitable 2) 此 TVisitable 的结果类型 (TResult) 应该是什么 3) 对每个 TVisitable 强制执行正确签名的访问方法,访问者实现是“能够访问”,像这样:
public class CountVisitor : IVisitor<int, Foo>
{
public int Visit(Foo visitable) => 42;
}
public class NameVisitor : IVisitor<string, Foo>
{
public string Visit(Foo visitable) => "Chewie";
}
非常愉快和美丽,这让我可以写:
var theFoo = new Foo();
int count = theFoo.Accept(new CountVisitor());
string name = theFoo.Accept(new NameVisitor());
很好。
现在悲伤的时刻开始了,当我添加另一个可访问类型时,例如:
public class Bar : IVisitable<Bar>
{
public TResult Accept<TResult>(IVisitor<TResult, Bar> visitor) => visitor.Visit(this);
}
可以通过CountVisitor 访问:
public class CountVisitor : IVisitor<int, Foo>, IVisitor<int, Bar>
{
public int Visit(Foo visitable) => 42;
public int Visit(Bar visitable) => 7;
}
这突然破坏了 Accept 方法中的类型推断! (这破坏了整个设计)
var theFoo = new Foo();
int count = theFoo.Accept(new CountVisitor());
给我:
“无法从用法推断出方法
'Foo.Accept<TResult>(IVisitor<TResult, Foo>)'的类型参数。”
谁能详细说明这是为什么? CountVisitor 实现的IVisitor<T, Foo> 接口只有一个版本- 或者,如果由于某种原因无法消除IVisitor<T, Bar>,则它们都具有相同的T - int,=没有其他type 无论如何都会在那里工作。一旦有不止一个合适的候选者,类型推断就会放弃吗? (有趣的事实:ReSharper 认为 theFoo.Accept<int>(...) 中的 int 是多余的:P,即使没有它就无法编译)
【问题讨论】:
标签: c# generics methods interface type-inference