如何在C#中为生成的类添加(非平凡的)多态实现?
例如,假设我的(不可修改的)生成器吐出一百个看起来像这样的类:
public partial class Table1 {
public int StatusID { get; set; }
// other properties, etc.
}
我想将这个属性添加到所有这些属性中:
public enum Statuses {
Unknown,
Good,
Error
}
public Statuses Status {
get { return (Statuses)StatusID; }
set { StatusID = (int)value; }
}
我怎样才能做到这一点?我不能使用基类,因为这将需要生成的属性上的overrides
。我不能使用接口,因为我想要实现,而不仅仅是定义。
您所描述的是mixin,如果没有IL编织(编译时)或动态代理(运行时),它在C#中不可用。
compile time迷信
基本上,您生成的类将存在于特殊程序集中,并且该属性将在编译器运行时添加。此特殊属性在程序集本身中不可见,但对程序集的使用者/用户可见。有Cilador和Mixins.Fody - 都是免费的,但都没有维护/停止。还有商业上的PostSharp,但提供免费版本,也可以获得这个。
动态代理
这里的目标将略有不同 - 使用代理将运行时类型替换为动态生成的类型。在框架中,可以使用RealProxy
,在dotnet核心中可以使用DispatchProxy
。在这两种情况下,这将比编译时mixin更不好用,我认为最好向您展示而不是解释:
Table1 table = ...
// this creates a proxy (dynamic type) which derives from Table1. This can be used to wrap ANY type with a status property
Table1 proxy = ProxyGenerator.WrapConcreteWithStatusProxy(table);
// the IStatusObject interface and implementation is being provided by the proxy, and is only accessible via a cast.
IStatusObject tableStatus = (IStatusObject)proxy;
tableStatus.Status = Statuses.Good;
如果您熟悉发射IL,则可以使用此方法实现高级别的自定义。
摘要:
我在编译时混音方面没有那么成功 - 免费的oss停止了库不能开箱即用,商业免费选项有限,尽管它们运行良好。从理论上讲,编译时mixin是更好的选择,因为它们可以提高性能,智能感知并避免运行时转换。
也就是说,动态代理肯定会工作并且更可靠。我在几十个项目中以这种或类似的方式使用了动态代理 - 在很多项目中我通过发送IL来自己生成动态类型。这也为您提供了使用status属性包装任何类型的额外好处,即使您在编译时不了解基类型也是如此。祝好运!