我为我的项目选择了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; }
}
我知道可能存在崩溃系统的风险(如果已经实例化了类),所以我正在寻找避免这个问题的最佳方法,并模仿我的需要。
答案 0 :(得分:4)
看来你在这里做的事情有两个部分。您需要动态创建类型以支持其他属性。您还需要确保在AppDomain中永远不会出现重复类型,即User
的两种不同定义。
已经给出的各种建议处理如何创建类型。在一个项目中,我们有类似的东西。我们创建了一个具有核心属性的基类和一个用于存储“扩展”属性的字典。然后我们使用Reflection.Emit
来创建具有所需属性的派生类型。每个属性定义只是从基类中的字典读取或写入。由于Reflection.Emit
需要编写低级IL代码,因此最初看起来很复杂。我们在另一个类库中编写了一些示例派生类并对其进行了编译。这些是我们在运行时实际需要实现的示例。然后我们使用ildasm.exe来查看编译器生成的代码。这使得我们可以很容易地弄清楚如何在运行时生成相同的代码。
您的第二个挑战是避免重复的类型名称。我们将guid(删除了无效字符)附加到每个生成类型的名称,以确保从未发生过。很容易解决,但我不知道你是否可以通过你的ORM来解决这个问题。
如果这是服务器代码,您还需要考虑在.NET中永远不卸载程序集的事实。因此,如果您在运行时重复生成新类型,您的流程将继续增长。客户端代码也会发生同样的情况,但如果您不希望该进程长时间运行,则可能不会出现问题。
我说装配没有卸下;但是,您可以卸载整个AppDomain
。因此,如果这是服务器代码,您可以在其自己的appdomain中运行整个操作,然后将其拆除以确保卸载动态创建的类型。
答案 1 :(得分:0)
为什么不为其所有属性使用键值对,或者至少使用动态值?
http://msdn.microsoft.com/en-us/library/system.collections.hashtable.aspx
你可以按照你用Reflection描述的方式来实现,但它会受到性能影响,这种方式也可以删除属性。
答案 2 :(得分:0)
我目前正在开展的项目有类似的要求。我们的系统已经投入生产,并且有一个客户请求添加字段。
我们通过简单地向我们的模型添加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; }
}
我们已经使用了几个星期而没有任何问题。
我们从中发现的另一个好处是每行可以有自己的自定义字段,因此我们可以按记录处理它们,而不是每条记录都需要它们。
答案 3 :(得分:0)
查看ExpandoObject
,它为执行此类操作提供动态语言支持。您可以使用它在运行时向POCO添加其他属性。以下是使用.NET的DLR功能的链接:http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject%28v=vs.100%29.aspx