一般来说,接口只能在编码时实现,但由于某些原因,无法在运行时实现。下面就介绍一种在运行时实现接口的解决方案。
在介绍之前,先学习这个方案中所需要的知识点是动态编译、委托和反射。
分析:
1、实现接口还是必须有一个类,一个“class ClassName : InterfaceName {...}”的类。顺着这个思路,会想到这个ClassName能否动态生成(运行时生成)。
2、动态生成类,有两种方式:动态编译和Emit技术(这里使用“动态编译”)。如果每实现一个类都需要动态编译,这样一定承担上影响性能,也占内存。所以思考这个类能不能是一个“模版类”,一个接口对应一个“动态实现的模版类”(当然,不同接口肯定是对应不同的“动态实现的模版类”),不同的实现,由你自己决定。
3、“动态实现的模版类”会想到委托。如:
public class ClassNameImplementTemplate : InterfaceName { private Dictionary<string, Delegate> _implements; // 具体实现的委托
// 实现接口的方法
public void Func()
{
// 这里执行_implements["Func"]的Delegate
}
}
在“动态实现的模版类(ClassNameImplementTemplate)”里维护一个具体实现列表,也就是一个委托列表。在“动态实现的模版类”中的实现接口的方法里,去对应执行这个委托列表的具体实现委托。
通过上面的分析,总结思路,步骤如下:
1、通过“动态实现接口”生成“动态实现的模版类”。
2、用户具体实现属性、方法、事件等。
3、用户实例化“动态实现的模版”对象。
按照上次的步骤,我们对其进行封装:RuntimeClass<Interface>类。类图如下:
该类包含了生成“动态实现的模版类”、用户实现方法、用户实现属性、用户触发事件(可在实现属性或方法中触发事件)以及最后的实例化。当用户需要动态实现接口ITry时,可用下面代码:
public interface ITry { string Prop1 { get; set; } event EventHandler Click; string Fun2(); } RuntimeClass<ITry> cls = new RuntimeClass<ITry>(); cls.ImplementProperty<string>("Prop1", // 具体实现Prop1属性 (@this) => // @this是实例本身,这样即可调用实例的其他方法或访问属性或触发事件 {
// 相当于属性的get return cls.Fields["prop1"].ToString(); // 字符 }, (@this, s) => {
// 相当于属性的set cls.Fields["prop1"] = s; }).ImplementMethod("Fun2", new Func<ITry, string>((@this) => // 具体实现Fun2方法 { cls.OnEventHandler(@this, "Click", null, EventArgs.Empty); //触发事件 @this.Prop1 = "3212"; return @this.Prop1; })
); ITry obj = (ITry)cls.CreateInstance();// 实例化 obj.Click += (sender, e) => // 注册事件 { MessageBox.Show("点击"); }; obj.Prop1 = "123"; // 属性赋值 string ss = obj.Prop1; // 获取属性 ss = obj.Fun2(); // 执行方法
VS2010,.net4 代码下载: http://download.csdn.net/detail/lyb018/4685241
通过这种解决方案,可以扩展出动态代理、拦截器等等。