Add property to POCO class at runtime

不打扰是莪最后的温柔 提交于 2019-11-29 10:08:41

It seems that there are two parts to what you're doing here. You need to create types dynamically to support the additional properties. You also need to ensure that you never end up with duplicate types in your AppDomain, i.e. two different definitions of User.

Runtime type generation

The various suggestions already given handle how to create the types. In one project, we had something similar. We created a base class that had the core properties and a dictionary to store the 'extension' properties. Then we used Reflection.Emit to create a derived type that had the desired properties. Each property definition simply read from or wrote to the dictionary in the base class. Since Reflection.Emit entails writing low-level IL code, it seems complex at first. We wrote some sample derived classes in another class library and compiled them. These were examples of what we'd actually need to achieve at runtime. Then we used ildasm.exe to see what code the compiler produced. This made it quite easy to work out how we could generate the same code at runtime.

Avoiding namespace collisions

Your second challenge is to avoid having duplicate type names. We appended a guid (with invalid characters removed) to the name of each generated type to make sure this never happened. Easy fix, though I don't know whether you could get away with that with your ORM.

If this is server code, you also need to consider the fact that assemblies are never unloaded in .NET. So if you're repeatedly generating new types at runtime, your process will continue to grow. The same will happen in client code, but this may be less of an issue if you don't expect the process to run for an extended period of time.

I said assemblies are not unloaded; however, you can unload an entire AppDomain. So if this is server code you could have the entire operation run in its own appdomain, then tear it down afterwards to ensure that the dynamically created types are unloaded.

Why not use a key value pair for all its properties, or at least the dynamic ones?

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

You can do it the way you're describing with Reflection but it will take a performance hit, this way will allow removal of properties also.

The project I'm currently working on has a similar requirement. We have a system already in production and had a client request addition fields.

We solved this by simply adding a CustomFields property to our model.

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; }  
}

We've been using this for a few weeks with no issues.

An additional benefit we found from this was that each row could have its own custom fields so we could handle them on a per record basis instead of requiring them for every record.

Check out the ExpandoObject, which provides dynamic language support for doing something like this. You can use it to add additional properties to your POCO's at runtime. Here's a link on using .NET's DLR features: http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject%28v=vs.100%29.aspx

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!