8

我为我的项目选择了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; }
}

我知道这样做可能会导致系统崩溃(如果类已经实例化),所以我正在寻找避免这个问题并模仿我的需求的最佳方法。

4

4 回答 4

4

您在这里所做的似乎有两个部分。您需要动态创建类型以支持其他属性。您还需要确保您的 AppDomain 中永远不会出现重复类型,即User.

运行时类型生成

已经给出的各种建议处理了如何创建类型。在一个项目中,我们有类似的东西。我们创建了一个基类,它具有核心属性和一个存储“扩展”属性的字典。然后我们用来Reflection.Emit创建具有所需属性的派生类型。每个属性定义都简单地从基类中的字典读取或写入。由于Reflection.Emit需要编写低级 IL 代码,因此乍一看似乎很复杂。我们在另一个类库中编写了一些示例派生类并编译了它们。这些是我们在运行时实际需要实现的示例。然后我们使用 ildasm.exe 来查看编译器生成了哪些代码。这使得我们很容易弄清楚我们如何在运行时生成相同的代码。

避免命名空间冲突

您的第二个挑战是避免使用重复的类型名称。我们在每个生成的类型的名称中附加了一个 guid(删除了无效字符),以确保这种情况永远不会发生。很容易解决,虽然我不知道你是否可以用你的 ORM 来解决这个问题。

如果这是服务器代码,您还需要考虑在 .NET 中永远不会卸载程序集这一事实。因此,如果您在运行时反复生成新类型,您的流程将继续增长。客户端代码中也会发生同样的情况,但如果您不希望进程运行较长时间,这可能不是问题。

我说没有卸载程序集;但是,您可以卸载整个AppDomain. 因此,如果这是服务器代码,您可以让整个操作在其自己的 appdomain 中运行,然后将其拆除以确保卸载动态创建的类型。

于 2013-01-28T17:04:52.490 回答
1

查看ExpandoObject,它为执行此类操作提供了动态语言支持。您可以使用它在运行时向您的 POCO 添加其他属性。这是使用 .NET 的 DLR 功能的链接:http: //msdn.microsoft.com/en-us/library/system.dynamic.expandoobject%28v=vs.100%29.aspx

于 2013-01-27T00:08:20.237 回答
0

为什么不对所有属性使用键值对,或者至少是动态属性?

http://msdn.microsoft.com/en-us/library/system.collections.hashtable.aspx

您可以按照您使用反射描述的方式进行操作,但它会影响性能,这种方式也允许删除属性。

于 2013-01-20T00:28:11.790 回答
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; }  
}

我们已经使用它几个星期了,没有任何问题。

我们从中发现的另一个好处是,每一行都可以有自己的自定义字段,因此我们可以在每条记录的基础上处理它们,而不是对每条记录都要求它们。

于 2013-01-23T18:06:13.303 回答