【发布时间】:2012-03-12 16:00:25
【问题描述】:
我正在编写一段处理 Windows 窗体控件的 C# 代码。这是一个小例子,一个小包装器,用于获取某些控件的边界矩形(在屏幕坐标中):
public class GUIObject {
protected Control m_control;
// [..]
public virtual Rectangle Bounds {
get {
Rectangle r = m_control.Bounds;
if ( m_control.Parent != null ) {
return m_control.Parent.RectangleToScreen( r );
}
return r;
}
}
}
此代码被编译成一个库,该库作为一个“插件”分发,以加载到客户的应用程序中。然而,事实证明,一些客户在他们的应用程序中使用的 Windows 窗体版本与我的插件所链接的版本不同。我的计划是通过使上述代码后期绑定来解决这个问题,以便它可以与当前应用程序域中加载的任何 Windows 窗体版本一起使用。在 .NET 4 中,我可以使用 dynamic 关键字,但遗憾的是,这段代码也应该适用于 .NET3 应用程序。因此,我开始使用反射 API,引入了一个小助手对象,这使得使用反射 API 变得更好:
public class LateBoundObject {
private Object m_o;
// [..]
public Object GetProperty( String name ) {
PropertyInfo pi = m_o.GetType().GetProperty( name );
return pi == null ? null
: pi.GetValue( m_o, null );
}
public Object InvokeMethod( String name, Object[] args ) {
MethodInfo mi = m_o.GetType().GetMethod( name );
return mi == null ? null
: mi.Invoke( m_o, args );
}
}
public class GUIObject {
protected LateBoundObject m_control;
// [..]
public virtual Rectangle Bounds {
get {
Object r = m_control.GetProperty( "Bounds" );
if ( r == null) {
return new Rectangle();
}
Object parent = m_control.GetProperty( "Parent" );
if ( parent != null ) {
LateBoundObject po = new LateBoundObject( parent );
r = po.InvokeMethod( "RectangleToScreen",
new Object[] { r } );
}
return (Rectangle)r;
}
}
}
不是很漂亮。调用方需要进行大量的转换,我怀疑我迟早也必须处理重载的方法或属性——前进的道路相当坎坷。理想情况下,包装对象将允许保持原始代码非常相同。
所以,在我开始修复 LateBoundObject 包装类之前,我想知道:还有其他人有使用反射 API 制作 C# 代码后期绑定的经验吗?如果是这样,您是如何处理它以将使用原始反射 API 的痛苦降至最低 - 您是否还使用了 LateBoundObject 的包装类,或者您是否采用了完全不同的路线?就原始代码而言,我正在寻找侵入性最小的方法。
【问题讨论】:
-
有多少个“WinForms 版本”?我认为你应该只针对 Fx2.0 的库,并为 Fx1 和可能为 Fx4 制作一个单独的库
-
@HenkHolterman:确实如此,对于 Windows 窗体,只需多次构建插件就足够了。但是,我在使用其他工具包(WPF 和许多 3rd 方工具包,如“扩展 WPF”)时也面临同样的问题。所以我想知道是否可以通过让我的代码后期绑定来避免多次构建所有内容。
-
您确定要让您的 Fx4 用户使用后期绑定的 Fx1.1 代码吗?
-
@HenkHolterman:还有多少负担还有待观察;我肯定会(在时间和空间上)分析生成的代码以检查它的成功率。在此之前,我首先想澄清一下使用反射 API 使现有的 C# 代码库后期绑定是否可行(可能通过使用一些便利的包装器)。
标签: c# .net late-binding