我选择ServiceStack OrmLite为我的项目是一个纯粹的面向数据的应用程序。 我愿意允许最终用户创建的,将被用来生成使用在运行时类中的XML格式定义自己的对象类型的CodeDOM 。
我也将定义应用程序(即需要进行一些“系统”对象User
),但我不能预见所有的最终用户将使用属性,因此,我正在寻找一种方式,让延长我在设计时创建的类。 样品波纹管
public class User
{
public Guid Uid { get; set; }
public String Username { get; set; }
public String Password { get; set; }
}
最终用户希望有一个Email
和Address
。 他应该能在2个属性添加到上层阶级和全类将(仍然可以通过使用OrmLite,因为它可以覆盖:
public class User
{
public Guid Uid { get; set; }
public String Username { get; set; }
public String Password { get; set; }
public String Email{ get; set; }
public String Address { get; set; }
}
我知道有可能这样做使系统崩溃(如果类已经实例化),所以我要寻找避免这个问题,并模仿需要我的最佳方式的风险。
它似乎有两个部分你在做什么这里。 您需要动态地创建类型,以支持额外的属性。 你还需要确保不会出现重复的类型在你的AppDomain,即两个不同的定义User
。
运行时类型代
已经给出了各种建议处理如何创建类型。 在一个项目中,我们有类似的东西。 我们创建了一个基类,有核心性能和存储“扩展”性质的字典。 然后,我们使用Reflection.Emit
创建派生类型具有良好的特性。 每个属性的定义简单地读或写在基类的字典。 由于Reflection.Emit
需要编写低级别的IL代码,它起初看似复杂。 我们在其他类库中写了一些样品派生类和编译他们。 这些是什么,我们会实际需要,以实现在运行时的例子。 然后,我们使用程序Ildasm.exe看到编译器产生什么代码。 这使得它很容易找出我们如何能够在运行时生成相同的代码。
避免命名空间冲突
你的第二个挑战是避免有重复的类型名。 我们追加一个GUID(含无效字符删除),以每个生成类型的名称,以确保这从来没有发生过。 简单的办法,虽然我不知道你是否能逃脱与您的ORM。
如果这是服务器代码,您还需要考虑的是,组件从未在.NET卸载。 因此,如果你反复在运行时产生新的类型,你的进程将继续增长。 同样将在客户端代码中发生的,但如果你不希望的过程,对于长时间运行,这可能是问题不大。
我说的组件不卸载; 但是,您可以卸载整个AppDomain
。 因此,如果这是服务器端的代码,你可以在自己的应用程序域整个操作运行,然后撕裂下来之后,以确保动态创建的类型被卸载。
为什么不使用其所有属性键值对,或者至少是动态的?
http://msdn.microsoft.com/en-us/library/system.collections.hashtable.aspx
你可以做你与反思描述的方式,但它会采取的性能损失,这种方式将允许除去性能也。
我目前工作的项目也有类似的要求。 我们已经有一个系统在生产中,有一个客户端请求另外的字段。
我们通过简单地增加一个CustomFields属性,我们的模型解决了这个。
public class Model: IHasId<Guid>
{
[PrimaryKey]
[Index(Unique = true)]
public Guid Id { get; set; }
// Other Fields...
/// <summary>
/// A store of extra fields not required by the data model.
/// </summary>
public Dictionary<string, object> CustomFields { get; set; }
}
我们已经使用了这个没有问题了几个星期。
我们从这个发现的另外一个好处是,每行可以有自己的自定义字段,这样我们就可以在每记录的基础处理他们,而不是要求他们对每条记录的。
退房ExpandoObject
,它提供了做这样的动态语言支持。 您可以使用它在运行时的附加属性您POCO的补充。 下面是使用.NET的DLR功能的链接: http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject%28v=vs.100%29.aspx