Dynamically Create C# Properties From Database Columns
I don't know if this can开发者_运维知识库 be done in C#/.NET 2.0 but I want to be able to add a sql call to a method and build the properties based off the call. So, it would be something like this:
QueryResult result = QueryDataTable.Query("SELECT ...", "DataConnection");
int someVar = result.SomeTableId;
So, above the SomeTableId property would actually exist until the "SELECT" statement. It checks for the columns and if exists creates the property
It's possible through the Reflection.Emit
namespace.
This is a piece of code I wrote before, it converts as DataTable
columns to a type, it may be helpful:
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
static class DataTableExtensions
{
public static Type GetTableType(DataTable DTable)
{
// Create needed TypeBuilder helpers
AppDomain myDomain = Thread.GetDomain();
AssemblyName myAsmName = new AssemblyName("Anonymous");
AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(myAsmName, AssemblyBuilderAccess.Run);
ModuleBuilder myModBuilder = myAsmBuilder.DefineDynamicModule(myAsmName.Name);
TypeBuilder myTypeBuilder = myModBuilder.DefineType(DTable.TableName, TypeAttributes.Public);
foreach (DataColumn col in DTable.Columns) {
var PropertyName = col.ColumnName;
var PropertyType = col.DataType;
FieldBuilder PropertyFieldBuilder = myTypeBuilder.DefineField("_" + PropertyName.ToLower, PropertyType, FieldAttributes.Private);
PropertyBuilder PBuilder = myTypeBuilder.DefineProperty(PropertyName, PropertyAttributes.HasDefault, col.DataType, null);
MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
MethodBuilder getPropertyBuilder = myTypeBuilder.DefineMethod("get" + PropertyName, getSetAttr, col.DataType, Type.EmptyTypes);
// Constructing IL Code for get and set Methods.
ILGenerator GetPropGenerator = getPropertyBuilder.GetILGenerator();
GetPropGenerator.Emit(OpCodes.Ldarg_0);
GetPropGenerator.Emit(OpCodes.Ldfld, PropertyFieldBuilder);
GetPropGenerator.Emit(OpCodes.Ret);
MethodBuilder setPropertyBuulder = myTypeBuilder.DefineMethod("set_" + PropertyName, getSetAttr, null, new Type[] { col.DataType });
ILGenerator SetPropGenerator = setPropertyBuulder.GetILGenerator();
SetPropGenerator.Emit(OpCodes.Ldarg_0);
SetPropGenerator.Emit(OpCodes.Ldarg_1);
SetPropGenerator.Emit(OpCodes.Stfld, PropertyFieldBuilder);
SetPropGenerator.Emit(OpCodes.Ret);
PBuilder.SetGetMethod(getPropertyBuilder);
PBuilder.SetSetMethod(setPropertyBuulder);
}
ConstructorInfo objCtor = typeof(object).GetConstructor(new Type[-1 + 1]);
ConstructorBuilder pointCtor = myTypeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
ILGenerator ctorIL = pointCtor.GetILGenerator();
// Constructing IL Code for the Type Constructor.
ctorIL.Emit(OpCodes.Ldarg_0);
ctorIL.Emit(OpCodes.Call, objCtor);
ctorIL.Emit(OpCodes.Ret);
return myTypeBuilder.CreateType();
}
}
Sure, it is possible to create a type at runtime, but it involves some fairly arcane black arts and I promise you it is more work than you want to do.
There is another solution to your requirements, i am sure.
What are you planning to do with the object that is created/modified?
perhaps another approach would be more appropriate.
If I understand you correctly you are looking for a dynamic type, that is a type whose properties are not know until runtime. Those are to my knowledge only possible in dotNet 4
Is there any reason that the columns returned by the select are unknown at build time?
Not possible in .NET Framework 2.0.
You could use a DataTable or KeyValuePairs to store the results.
How would you know at compile time, something that is not settled before runtime? This is dynamical binding, and you can't do it like that.
If anything you could modify you type at runtime with reflection.emit and use reflection to bind to the method at runtime.
But you are probably going about this the wrong way.
I don't know if it's because you don't know the columns before you execute the query, in which case you should probably just store results in a keyvaluepair as suggested - otherwise you could just map to an existing type.
精彩评论