C# c语言中减少代码复制的惯用方法# 我是C语言中的新成员(我来自C++),我面对一个简单的模式,C++中我会用模板来解决,但是同样的方法不能用C语言泛型。 下一个代码(C++与C++模板的混合)显示了我的问题。 class A { /* ... */ } class B { /* ... */ } // C, D, ... class W { public void Update(A a) { /* ... */ } public void Update(B b) { /* ... */ } // C, D, ... } class X { template <typename T> public void Update(IEnumerable<T> vs) { if (vs.any(vs => CreateOrUpdate(v))) { doStuff(); } } template <typename T> public void Update(T v) { if (CreateOrUpdate(v)) { doStuff() } } template <typename T> private bool CreateOrUpdate(T v) { W w; bool updated = false; if (!m.TryGetValue(v.Id, out w)) { w = new W(v.Id); m.Add(w.Id, w); updated = true; } return w.Update(v) || updated; } private Dictionary<string, W> m; } A类{/*…*/} B类{/*…*/} //C,D。。。 W类 { 公共无效更新(A){/*…*/} 公共无效更新(B){/*…*/} //C,D。。。 } X类 { 模板 公共无效更新(IEnumerable vs){ 如果(vs.any(vs=>CreateOrUpdate(v))){ doStuff(); } } 模板 公共无效更新(TV) { 如果(创建或更新(v)){ 多斯塔夫() } } 模板 私有布尔CreateOrUpdate(电视) { W; bool updated=false; 如果(!m.TryGetValue(v.Id,out w)){ w=新w(v.Id); m、 添加(w.Id,w); 更新=真; } 返回w.Update(v)| | updated; } 私人词典m; }
即使C# c语言中减少代码复制的惯用方法# 我是C语言中的新成员(我来自C++),我面对一个简单的模式,C++中我会用模板来解决,但是同样的方法不能用C语言泛型。 下一个代码(C++与C++模板的混合)显示了我的问题。 class A { /* ... */ } class B { /* ... */ } // C, D, ... class W { public void Update(A a) { /* ... */ } public void Update(B b) { /* ... */ } // C, D, ... } class X { template <typename T> public void Update(IEnumerable<T> vs) { if (vs.any(vs => CreateOrUpdate(v))) { doStuff(); } } template <typename T> public void Update(T v) { if (CreateOrUpdate(v)) { doStuff() } } template <typename T> private bool CreateOrUpdate(T v) { W w; bool updated = false; if (!m.TryGetValue(v.Id, out w)) { w = new W(v.Id); m.Add(w.Id, w); updated = true; } return w.Update(v) || updated; } private Dictionary<string, W> m; } A类{/*…*/} B类{/*…*/} //C,D。。。 W类 { 公共无效更新(A){/*…*/} 公共无效更新(B){/*…*/} //C,D。。。 } X类 { 模板 公共无效更新(IEnumerable vs){ 如果(vs.any(vs=>CreateOrUpdate(v))){ doStuff(); } } 模板 公共无效更新(TV) { 如果(创建或更新(v)){ 多斯塔夫() } } 模板 私有布尔CreateOrUpdate(电视) { W; bool updated=false; 如果(!m.TryGetValue(v.Id,out w)){ w=新w(v.Id); m、 添加(w.Id,w); 更新=真; } 返回w.Update(v)| | updated; } 私人词典m; },c#,templates,generics,design-patterns,C#,Templates,Generics,Design Patterns,即使A,B,…实现像interface IId{string Id{get;}}这样的接口,并且我使用泛型public void Update(IEnumerable vs):其中T:IId,由于w.Update(v)(需要添加public bool Update(IId))W中的,但此方法将始终被调用) 从理论的角度理解C泛型与C++模板的区别,以及为什么代码> W.Update(V)< /C>不能静态地从 W > 更新>代码>方法之间调用。但是,我无法找出解决此问题的最佳方法。一种方法确实是
A,B,…
实现像interface IId{string Id{get;}}
这样的接口,并且我使用泛型public void Update(IEnumerable vs):其中T:IId
,由于w.Update(v)
(需要添加public bool Update(IId))W
中的
,但此方法将始终被调用)
从理论的角度理解C泛型与C++模板的区别,以及为什么代码> W.Update(V)< /C>不能静态地从<代码> W<代码> > <代码>更新>代码>方法之间调用。但是,我无法找出解决此问题的最佳方法。一种方法确实是向类
W
添加一个方法public bool Update(IId id)
,但您需要动态调度参数id
:
class W
{
public bool Update(IId id)
{
dynamic d_id = id;
return Update(d_id);
}
// ...
}
程序将在运行时确定调用哪个Update
函数,因为d_id
被声明为dynamic
如果您添加另一个实现IId
的类E
,但忘记实现Update(ee)
,则上述Update
函数将递归调用其自身,直到内存不足。通过将Update(IId id)
重命名为DoUpdate(IId id)
并在CreateOrUpdate
中调用DoUpdate,可以避免无限递归的危险。然后,您将得到一个有意义的异常,说明类型为E
的id
无法调度
MSDN上有一个很好的答案可能会对您有所帮助。可能会有更好的答案,但以下是我的看法
假设A
和B
都实现了包含属性Id
的接口IId
。我将在这些类中要实现的接口中添加一个方法Update(W)
,这样您可以编写:
private bool CreateOrUpdate(T v)
{
W w;
bool updated = false;
if (!m.TryGetValue(v.Id, out w)) {
w = new W(v.Id);
m.Add(w.Id, w);
updated = true;
}
return v.Update(w) || updated;
}
这样,您就可以对每种情况都一视同仁,这基本上就是接口的要点(而不是玩弄typeof
开关和糟糕的性能反射)。在我看来,这是解决问题的更好的面向对象方法。这被称为
顺便说一下,你可以写:
class X<T> where T : IId
X类,其中T:IId
而不是编写泛型方法(类将变为泛型而不是其方法)。它必须在语义上有意义,因此我无法真正区分您的具体情况(类名被混淆)。请将问题标记为适当的-是C#问题吗?是的。实际上,它被标记为c。(我不知道你的意思)是C++吗?如果没有,请删除标记。您的意思是:但是,此方法将始终被调用?但是,如果您希望减少代码重复,您不应该更喜欢在W
中使用单个更新(IId id)
方法吗?或者更新(T id),其中T:IId
?谢谢。我认为在一个类似的解决方案中使用多态性,但没有你的优雅。我假设没有办法避免运行时检查,对吗?您可以实现访问者模式,如下所示。IMHO,访问者模式一点也不优雅,因为它只是一种手动实现动态调度的侵入性方式。这是我提出的解决方案,但正如您所说,在我的案例A中,B。。。不应该知道W。对不起,你能确认没有运行时检查就没有解决方案吗?在运行时解决这个问题类似于强制转换,你不知道它是否能工作,直到你实际运行你的应用程序,并且你有可能遇到运行时异常(或者更糟糕的是,在这种情况下,堆栈溢出)。我会避免这种情况,因为您失去了类型安全性,而且它确实表明存在代码气味。@Groo,我有什么选择?如果我希望代码是类型安全的,避免代码重复,我可以只添加“public void W::Update(A){genericUpdate(A);}”,并将genericUpdate设置为private。Update(W)
的主体应该是W.Update(this)
,我想?因此,您的方法通常被称为visitor或double dispatch模式,这是一种手动实现动态调度的方法(以类型安全的方式授予);这要视情况而定。我想说,这两种方法都是合理的:)我同意。有时我倾向于使用这两种模式。