I have a class "Forecast":
public class Forecast
{
public int Id { get; set; }
public int Description{ get; set; }
}
In certain Case I add new fields for the Class Forecast depends on Parameter sing Reflection.
So the returned object it can be like this outputs:
Output 1
{{
"Id": "1",
"Description": "Scenario 1",
"fc": "-45156,60000",
"fci": "-45156,60000",
"fcii": null,
"fciii": null,
"fciv": null,
}}
Output 2
{{
"Id": "1",
"Description": "Scenario 2",
"fc": "-45156,60000",
"fci": "-45156,60000",
}}
Output 3
{{
"Id": "1",
"Description": "Scenario 3",
"fc": "-45156,60000",
"fci": "-45156,60000",
"fcii": null,
}}
Output 4
{{
"Id": "1",
"Description": "Scenario 4",
"fc": "-45156,60000",
}}
As you see there are dynamic Fields as an result in 4 Scenarios.
How I can cast it to Class Forecast?
Update:
Create a new field in Runtime
public class MyObjectBuilderApi
{
public static Type objType { get; set; }
public MyObjectBuilderApi()
{
objType = null;
}
/// <summary>
/// Create new object
/// </summary>
/// <param name="Fields">Fields</param>
/// <returns>Object</returns>
public static object CreateNewObject(List<FieldApi> Fields,
string name = "MyDynamicType", Type type = null)
{
objType = CompileResultType(Fields, name, type);
var myObject = Activator.CreateInstance(objType);
return myObject;
}
/// <summary>
/// Create new type
/// </summary>
/// <param name="Fields">Fields</param>
/// <param name="name">name</param>
/// <param name="type">type</param>
/// <returns></returns>
public static Type CreateNewType(List<FieldApi> fields, string name = "MyDynamicType", Type type = null
, params AttributeBuilder[] builder)
{
return SharedModule.Config.Types.FirstOrDefault(x => x.Name == name) ?? CompileResultType(fields, name, type, builder);
}
/// <summary>
///
/// </summary>
/// <param name="genericInstance">generic Instance</param>
/// <param name="sortExpression">sort Expression</param>
/// <returns></returns>
public static MethodInfo GetCompareToMethod(object genericInstance,
string sortExpression)
{
Type genericType = genericInstance.GetType();
object sortExpressionValue = genericType.GetProperty(sortExpression)?
.GetValue(genericInstance, null);
Type sortExpressionType = sortExpressionValue?.GetType();
MethodInfo compareToMethodOfSortExpressionType = sortExpressionType?
.GetMethod("CompareTo", new Type[] { sortExpressionType });
return compareToMethodOfSortExpressionType;
}
/// <summary>
///
/// </summary>
/// <param name="Fields">Fields</param>
/// <param name="name">name</param>
/// <param name="type">type</param>
/// <returns></returns>
public static Type CompileResultType(List<FieldApi> Fields, string name, Type type, params AttributeBuilder[] builder)
{
TypeBuilder tb = GetTypeBuilder(type, name);
tb.DefineDefaultConstructor(MethodAttributes.Public
| MethodAttributes.SpecialName
| MethodAttributes.RTSpecialName);
// NOTE: assuming your list contains Field objects with fields FieldName(string) and FieldType(Type)
foreach (var field in Fields)
CreateProperty(tb, field.FieldName, field.FieldType);
foreach (var attributeBuilder in builder)
{
var displayNameAttributeBuilder = CreateCustomAttribute(attributeBuilder);
tb.SetCustomAttribute(displayNameAttributeBuilder);
}
// I was commented this code because the exception below was occured when lunch solution 21/07/2022
//'PdAssociatePlanInvoiceTemp', on 'Microsoft.EntityFrameworkCore.DbContextOptions`1[TContext]'
//violates the constraint of type parameter 'TContext'
/*ConstructorBuilder myConstructorBuilder = tb.DefineConstructor(MethodAttributes.Public
| MethodAttributes.SpecialName
| MethodAttributes.RTSpecialName,
CallingConventions.Standard,new []
{
typeof(DbSet<>)
.MakeGenericType( typeof(DbContextOptions<>) .MakeGenericType(tb.UnderlyingSystemType ))
});
var baseConstructor = type
.GetConstructor(BindingFlags.Public | BindingFlags.FlattenHierarchy |
BindingFlags.Instance,
null, new Type[0], null);
ILGenerator myConstructorIL = myConstructorBuilder.GetILGenerator();
myConstructorIL.Emit(OpCodes.Ldarg_0);
myConstructorIL.Emit(OpCodes.Ldarg_1);
myConstructorIL.Emit(OpCodes.Call, baseConstructor);
myConstructorIL.Emit(OpCodes.Nop);
myConstructorIL.Emit(OpCodes.Nop);
myConstructorIL.Emit(OpCodes.Ret);*/
Type objectType = tb.CreateType();
SharedModule.Config.Types.Add(objectType);
return objectType;
}
private static CustomAttributeBuilder CreateCustomAttribute(AttributeBuilder x)
{
if (x.Types == null)
{
x.Types = Type.EmptyTypes;
x.Values = Array.Empty<object>();
}
var constructorInfo = x.Attribute.GetConstructor(x.Types);
var displayNameAttributeBuilder = x.Properties == null ? new CustomAttributeBuilder(constructorInfo, x.Values) :
new CustomAttributeBuilder(constructorInfo, x.Values,
x.Properties
.Select(prop => x.Attribute
.GetProperty(prop)).ToArray(), x.PropertiesValues,
Array.Empty<FieldInfo>(), Array.Empty<object>());
return displayNameAttributeBuilder;
}
private static TypeBuilder GetTypeBuilder(Type type, string name)
{
var typeSignature = name;
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()),
AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature
, TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout
, type);
return tb;
}
private static void CreateProperty(TypeBuilder tb, string propertyName,
string propertyType)
{
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType.GetType(),
FieldAttributes.Private);
PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName,
PropertyAttributes.HasDefault, propertyType.GetType(), null);
MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName,
MethodAttributes.Public | MethodAttributes.SpecialName |
MethodAttributes.HideBySig, propertyType.GetType(), Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr =
tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] { propertyType.GetType() });
ILGenerator setIl = setPropMthdBldr.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}
Then I genereate the field with this, as an input an Int(nbForecast=4)
var fields = GenerateFields(nbForecast);
hen I Create the new Object
var newObjectForecast= MyObjectBuilderApi.CreateNewObject(fields, typeof(Forecast).Name, typeof(Forecast));
So at the end I assigned the fields to my object, my Problem how linkit with the rturned json from the Backend?
You can use the JsonExtensionDataAttribute that JSON.Net provides
var json=#"{
""Id"": ""1"",
""Description"": ""Scenario 2"",
""fc"": ""-45156,60000"",
""fci"": ""-45156,60000"",
}";
Forecast forecast = JsonConvert.DeserializeObject<Forecast>(json);
string fci= (string) forecast.Extra["fci"]; // "-45156,60000"
class
public class Forecast
{
public int Id { get; set; }
public string Description { get; set; }
[JsonExtensionData]
public Dictionary<string, object> Extra { get; set; }
}
or you can put the extra properties in a list
public class ForecastExtra : Forecast
{
[JsonExtensionData]
private Dictionary<string, object> ExtraDict { get; set; }
[JsonIgnore]
public List<KeyValuePair<string, string>> ExtraList
{
get
{
return ExtraDict?
.Select(kvp => new KeyValuePair<string, string>(kvp.Key, (string)kvp.Value))
.Where(kvp => kvp.Value != null)
.ToList();
}
}
}
Update
You don't any reflection to add one more item. Just add it to a dictionary.
data.ExtraDict.Add("fcivi","-45158,60001");
but if you want it a hard way, using reflections
foreach (var prop in data.ExtraList
{
var propertyName=prop.Key;
var propertyValue=(string) prop.Value;
// use reflections to add the property to the class instance
}
but it has nothing to do with json tag in your question, it needs a special post. But I don't think that you find an answer, since it doesn't make any sense at all. You can't use forecast.Extra["fci"] nor forecast.fci in your code since you don't know what properties json contains.
Related
I am trying to build dynamic types, inherited from a base object, based on a definition object (fieldnames/types) and then apply (potentially multiple) interfaces to that.
The base type has an object array to store values. The getters and setters use a generic method in the base type to save a specific type to an array location.
The "CreateType" works, but when I try to instantiate the object, I get:
System.InvalidProgramException : Common Language Runtime detected an invalid program.
I can't tell where the failure occurs.
Here is the Object definition:
public class UTObjectDef : IUTObjectDef
{
List<UTFieldDef> fieldDefs = new List<UTFieldDef>();
Dictionary<string, Type> interfaces = new Dictionary<string,Type>();
List<string> nameMap = new List<String>();
public string Name {get; set;}
public IUTFieldDef[] FieldDefs {
get {
return fieldDefs.ToArray();
}
}
public Type[] Interfaces {
get {
return interfaces.Values.ToArray();
}
}
public UTObjectDef(string name) {
Name = name;
}
public UTObjectDef(Type fromInterface) {
PropertyInfo[] props = fromInterface.GetProperties();
Name = fromInterface.Name;
if (Name.ToUpper().StartsWith("I")) {
Name = Name.Substring(1);
}
foreach( PropertyInfo prop in props) {
AddField(prop.Name, prop.PropertyType);
}
interfaces.Add(Name, fromInterface);
}
public void AddField(string name, Type fieldType)
{
var fieldDef = new UTFieldDef(name, fieldType);
fieldDefs.Add(fieldDef);
nameMap.Add(name);
}
public int FieldIndex(string fieldName) {
return nameMap.IndexOf(fieldName);
}
}
And the field definition:
public class UTFieldDef : IUTFieldDef
{
public string FieldName {get; set;}
public Type FieldType {get; set;}
public int? Length {get; set;}
public int? Decimals {get; set;}
public UTFieldDef(string fieldName, Type fieldType) {
FieldName = fieldName;
FieldType = fieldType;
}
}
The base type (Note: The constructor sets the arrays to the right size based on the field count), and the static UTObjectDef is populated through an Initialize static method, added in the TypeBuilder):
public class UTObject : IUTObject{
protected Object?[] values = new Object[0];
protected Object?[] origValues = new Object[0];
public T? getValue<T>(int index) {
return (T?)values[index];
}
public void setValue<T>(int index, T? value) {
values[index] = value;
}
}
And the dynamic object construction:
public static void buildTypes() {
MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run);
ModuleBuilder mb = ab.DefineDynamicModule(aName.Name);
Type baseType = typeof(UTObject.UTObject);
Type objDefType = typeof(UTObjectDef);
var valuesField = baseType.GetField("values", BindingFlags.NonPublic | BindingFlags.Instance);
var origValuesField = baseType.GetField("origValues", BindingFlags.NonPublic | BindingFlags.Instance);
foreach (UTObjectDef oDef in objectDefs.Values) {
TypeBuilder tb = mb.DefineType( oDef.Name, TypeAttributes.Public, baseType);
// Create a static field to hold the value.
const string FieldName = "ObjectDef";
var field = tb.DefineField(
FieldName,
objDefType,
FieldAttributes.Static | FieldAttributes.InitOnly | FieldAttributes.Public);
// Create a method to initialize the field.
const string InitializeMethodName = "Initialize";
var initMethod = tb.DefineMethod(
InitializeMethodName,
MethodAttributes.Static | MethodAttributes.Private,
CallingConventions.Standard,
typeof(void),
new[] { objDefType });
var il = initMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Stsfld, field);
il.Emit(OpCodes.Ret);
System.Type[] param = {};
Type invalOp = typeof(InvalidOperationException);
ConstructorInfo invOpExInfo = invalOp.GetConstructor(
Type.EmptyTypes
);
ConstructorInfo baseCon = baseType.GetConstructor(Type.EmptyTypes);
ConstructorBuilder ctor = tb.DefineConstructor( MethodAttributes.Public, CallingConventions.Standard, param );
ILGenerator cil = ctor.GetILGenerator();
Label isInit = cil.DefineLabel(); // define label to jump in case condition is false
MethodInfo getFldDefsInfo = objDefType.GetMethod("get_FieldDefs");
cil.Emit(OpCodes.Ldarg_0);
cil.Emit(OpCodes.Call, baseCon );
cil.Emit(OpCodes.Ldsfld, field);
cil.Emit(OpCodes.Ldnull);
cil.Emit(OpCodes.Ceq);
cil.Emit(OpCodes.Brfalse, isInit);
cil.Emit(OpCodes.Nop);
cil.Emit(OpCodes.Ldstr, "Not Initialized");
cil.Emit(OpCodes.Newobj, invOpExInfo);
cil.ThrowException(invalOp);
cil.MarkLabel(isInit);
cil.Emit(OpCodes.Nop);
cil.Emit(OpCodes.Ldarg_0);
cil.Emit(OpCodes.Call, getFldDefsInfo);
cil.Emit(OpCodes.Ldlen);
cil.Emit(OpCodes.Conv_I4);
cil.Emit(OpCodes.Newarr, typeof(System.Object));
cil.Emit(OpCodes.Stfld, valuesField);
cil.Emit(OpCodes.Ldarg_0);
cil.Emit(OpCodes.Call, getFldDefsInfo);
cil.Emit(OpCodes.Ldlen);
cil.Emit(OpCodes.Conv_I4);
cil.Emit(OpCodes.Newarr, typeof(System.Object));
cil.Emit(OpCodes.Stfld, origValuesField);
cil.Emit(OpCodes.Ret);
MethodInfo[] methods = typeof(UTObject.UTObject).GetMethods();
MethodInfo? getMethod = null;
MethodInfo? setMethod = null;
foreach(MethodInfo mi in methods) {
if (mi.Name.Contains("getValue") && mi.IsGenericMethod) {
getMethod = mi;
}
if (mi.Name.Contains("setValue") && mi.IsGenericMethod) {
setMethod = mi;
}
}
for (int i = 0; i < oDef.FieldDefs.Length; i++ )
{
IUTFieldDef fDef = oDef.FieldDefs[i];
PropertyBuilder fldPropBldr = tb.DefineProperty(fDef.FieldName,
PropertyAttributes.None,
fDef.FieldType,
null);
MethodBuilder getMethodBuilder = tb.DefineMethod("get_" + fDef.FieldName,
getSetAttr,
fDef.FieldType,
Type.EmptyTypes);
if (getMethod != null) {
ILGenerator GetPropGetIL = getMethodBuilder.GetILGenerator();
LocalBuilder fldIdx = GetPropGetIL.DeclareLocal(typeof(Int32));
MethodInfo getMethodInfo = getMethod.MakeGenericMethod(fDef.FieldType);
GetPropGetIL.Emit(OpCodes.Ldc_I4, i);
GetPropGetIL.Emit(OpCodes.Stloc, fldIdx);
GetPropGetIL.Emit(OpCodes.Ldarg_0);
GetPropGetIL.Emit(OpCodes.Ldloc, fldIdx);
GetPropGetIL.Emit(OpCodes.Call, getMethodInfo);
GetPropGetIL.Emit(OpCodes.Ret);
}
MethodBuilder setMethodBuilder = tb.DefineMethod("set_" + fDef.FieldName,
getSetAttr,
null,
new Type[] { fDef.FieldType });
if (setMethod != null) {
ILGenerator SetPropGetIL = setMethodBuilder.GetILGenerator();
LocalBuilder fldIdx = SetPropGetIL.DeclareLocal(typeof(Int32));
SetPropGetIL.Emit(OpCodes.Ldc_I4, i);
SetPropGetIL.Emit(OpCodes.Stloc, fldIdx);
SetPropGetIL.Emit(OpCodes.Ldarg_0);
SetPropGetIL.Emit(OpCodes.Ldloc, fldIdx);
SetPropGetIL.Emit(OpCodes.Call, setMethod.MakeGenericMethod(fDef.FieldType));
SetPropGetIL.Emit(OpCodes.Nop);
SetPropGetIL.Emit(OpCodes.Ret);
}
fldPropBldr.SetGetMethod(getMethodBuilder);
fldPropBldr.SetSetMethod(setMethodBuilder);
}
/* foreach(Type interfaceType in oDef.Interfaces) {
tb.AddInterfaceImplementation(interfaceType);
}
*/
Type? newType = tb.CreateType();
// Invoke the initializer method using reflection, passing the provided value to initialize the new field.
MethodInfo initMethodInfo = newType.GetMethod(InitializeMethodName, BindingFlags.Static | BindingFlags.NonPublic);
if (initMethodInfo != null) {
initMethodInfo.Invoke(null, new object[] { oDef });
}
foreach(Type interfaceType in oDef.Interfaces) {
objectTypesByInterface.Add(interfaceType.Name, newType);
}
}
I have been working on small library to build very simple types dynamically using AssemblyBuilder. I can build a type, add properties into it. But the problem I am facing is adding a property given a dynamically generated type that was also generated using this simple library. In other works, creating a complex type. I tried adding namespace to the type, but I think the source of my problem is not importing the nested type while creating the parent type.
How I create the type and nested type:
var token = "TestNameSpace";
var nestedType = Builders.CustomTypeBuilder.New(#namespace: token).AddProperty<string>("NestedProp").Compile();
var propertyName = "NestedProp";
var obj = Builders.CustomTypeBuilder.NewExtend<DummyClass>(#namespace: token)
.AddProperty(propertyName, nestedType)
.Instantiate<DummyClass>();
The nested type (or NestedProp) is kind of undefined ("Unresolved ...").
The main logic behind the library:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using CustomTypeBuilder.Extensions;
using static CustomTypeBuilder.Utilities.TypeUtility;
namespace CustomTypeBuilder
{
/// <summary>
/// Creates a new type dynamically
/// </summary>
public class CustomTypeGenerator
{
private readonly TypeBuilder _typeBuilder;
private readonly Dictionary<string, Type> _properties;
/// <summary>
/// Initialize custom type builder
/// </summary>
/// <param name="name"></param>
/// <param name="parentType"></param>
/// <param name="namespace"></param>
public CustomTypeGenerator(string name = null, Type parentType = null, string #namespace = null)
{
var assemblyName = RandomSafeString("DynamicAseembly");
var typeSignature = name ?? RandomSafeString("DynamicType");
// add namespace
if (#namespace != name)
{
typeSignature = $"{#namespace}.{typeSignature}";
}
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule(RandomSafeString("Module"));
_typeBuilder = moduleBuilder.DefineType(typeSignature,
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
parentType);
_typeBuilder.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
_properties = new Dictionary<string, Type>();
}
/// <summary>
/// Add attribute to the class
/// </summary>
/// <param name="attribute"></param>
public void AddAttribute(Attribute attribute)
{
_typeBuilder.SetCustomAttribute(attribute.BuildCustomAttribute());
}
/// <summary>
/// Compile the type builder to a type
/// </summary>
/// <returns></returns>
public Type CompileResultType()
{
return _typeBuilder.CreateType();
}
/// <summary>
/// Add interfaces to a type
/// </summary>
/// <param name="type"></param>
public void AddInterface(Type type)
{
if (!type.IsInterface)
{
throw new ArgumentException("Type was expected to be an interface");
}
_typeBuilder.AddInterfaceImplementation(type);
// add types in interface
type.GetProperties().ForEach(x => AddProperty(x.Name, x.PropertyType));
}
public void ExtendType(Type type)
{
_typeBuilder.SetParent(type);
}
public void AddProperty(string propertyName, Type propertyType)
{
if (!IsValidName(propertyName)) throw new ArgumentException("Property name does not follow to C# type system");
if (_properties.Keys.Any(x => x == propertyName)) throw new ArgumentException("Duplicate property name");
// add property to dictionary
_properties.Add(propertyName, propertyType);
var fieldBuilder = _typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
var propertyBuilder = _typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
var getPropMthdBldr = _typeBuilder.DefineMethod("get_" + propertyName,
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType,
Type.EmptyTypes);
var getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
var setPropMthdBldr = _typeBuilder.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] {propertyType});
var setIl = setPropMthdBldr.GetILGenerator();
var modifyProperty = setIl.DefineLabel();
var exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}
}
Any help would be appreciated. Thank you.
While not exactly a solution to your problem, I hope some of this information helps.
The debugger from Visual Studio 2017 and .NET Core 2.0 seems to display the type/object okay.
The nested type can be set and displayed correctly too.
It also appears to work correctly in VS Code
Curiously, the Rider debugger and .NET Core 2.0 appears to be able to identify the nested property type correctly when we instantiate and assign an object of nestedType before constructing the other object type that uses it, but it doesn't work if we merely instantiate it.
e.g.
var token = "TestNameSpace";
var nestedType = Builders.CustomTypeBuilder.New(#namespace: token).AddProperty<string>("NestedProp").Compile();
var propertyName = "NewProperty";
var someInstance = Activator.CreateInstance(nestedType);
var obj = Builders.CustomTypeBuilder.NewExtend<DummyClass>(#namespace: token)
.AddProperty(propertyName, nestedType)
.Instantiate<DummyClass>();
var nestedValue = Activator.CreateInstance(nestedType);
nestedType.GetProperty("NestedProp").SetValue(nestedValue, "NestedValue");
obj.GetType().GetProperty(propertyName).SetValue(obj, nestedValue);
Debugger.Break();
vs.
var token = "TestNameSpace";
var nestedType = Builders.CustomTypeBuilder.New(#namespace: token).AddProperty<string>("NestedProp").Compile();
var propertyName = "NewProperty";
// Instantiated, but not assigned to a local variable
Console.WriteLine(Activator.CreateInstance(nestedType));
var obj = Builders.CustomTypeBuilder.NewExtend<DummyClass>(#namespace: token)
.AddProperty(propertyName, nestedType)
.Instantiate<DummyClass>();
var nestedValue = Activator.CreateInstance(nestedType);
nestedType.GetProperty("NestedProp").SetValue(nestedValue, "NestedValue");
obj.GetType().GetProperty(propertyName).SetValue(obj, nestedValue);
Debugger.Break();
If however, we create the nested type, instantiate it and assign it to a variable in a separate scope first, then it seems to depend on whether the debugger paused after the assignment or not.
e.g.
static Type CreateNestedType()
{
var nestedType = Builders.CustomTypeBuilder.New(#namespace: "TestNameSpace")
.AddProperty<string>("NestedProp")
.Compile();
var x = Activator.CreateInstance(nestedType);
Console.WriteLine(x.GetType());
// Toggling this line changes the behaviour of the debugger at the *next* breakpoint.
//Debugger.Break();
return nestedType;
}
static void Main(string[] args)
{
var nestedType = CreateNestedType();
var propertyName = "NewProperty";
var obj = Builders.CustomTypeBuilder.NewExtend<DummyClass>(#namespace: "TestNameSpace")
.AddProperty(propertyName, nestedType)
.Instantiate<DummyClass>();
var nestedValue = Activator.CreateInstance(nestedType);
nestedType.GetProperty("NestedProp").SetValue(nestedValue, "NestedValue");
obj.GetType().GetProperty(propertyName).SetValue(obj, nestedValue);
Debugger.Break();
}
When actually using the objects within the program, they seem to behave correctly despite not appearing correctly in the debugger.
When I compiled and saved the dynamic assemblies using .NET Framework instead of .NET Core, they both pass PEVerify.
Rider seems to handle all of the above cases when we define both of the types in the same dynamic assembly/module instead of using a new dynamic assembly for each type.
Based on all of this it seems plausible that this is an issue/bug/missing feature/shortcoming (whatever you want to call it) in Rider's debugger, you may want to raise it directly with JetBrains to see if they can shed any more light on the situation.
I'm trying to acces the property of the class my Methodbuilder method is being defined in.
This is my current code:
Type[] types = { typeof(HttpListenerContext) };
TypeBuilder tb = GetTypeBuilder(type.Name);
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
MethodBuilder mB = tb.DefineMethod("Init", MethodAttributes.Public | MethodAttributes.Virtual, null, types);
ILGenerator il = mB.GetILGenerator();
il.Emit(OpCodes.Ldstr, typeof(Page).GetProperty("_POST").GetValue(??));
il.Emit(OpCodes.Call, typeof(DataSet).GetMethod("SetData"));
il.Emit(OpCodes.Ret);
tb.DefineMethodOverride(mB, typeof(Page).GetMethod("Init"));
try
{
Type tc = tb.CreateType();
Page test = (Page)Activator.CreateInstance(tc);
test.Init();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
This is is class I'm trying to get the property from:
public class Page
{
public Dictionary<string, string> _POST { get; set; }
public Dictionary<string, string> _GET { get; set; }
public Head Headers { get; set; }
public string ContentType { get; set; }
public int StatusCode = 200;
public virtual void Init(HttpListenerContext ctx = null) { }
public virtual void Load() { }
public virtual string Send() { return ""; }
public virtual string Send(string response) { return ""; }
}
The current typebuilder has Page as parent, how can I get a nonstatic value set in my typebuilder class? Like how could I get my method to Console.WriteLine the value of _POST?
private TypeBuilder GetTypeBuilder(string name)
{
string typeSignature = name;
AssemblyName aN = new AssemblyName(typeSignature);
AssemblyBuilder aB = AppDomain.CurrentDomain.DefineDynamicAssembly(aN, AssemblyBuilderAccess.Run);
ModuleBuilder mB = aB.DefineDynamicModule("MainModule");
TypeBuilder tB = mB.DefineType(typeSignature + "h",
TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout,
typeof(Page));
return tB;
}
ILGenerator il = mB.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldstr, typeof(Page).GetProperty("ContentType").GetGetMethod());
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
il.Emit(OpCodes.Ret);
tb.DefineMethodOverride(mB, typeof(Page).GetMethod("Init"));
I'm setting the value of ContentType before I'm getting it with my function.
It seems like you're creating an instance method on a type that inherits from Page. If that's the case, this is the code you want:
il.Emit(OpCodes.Ldarg_0); // Load the this reference
il.Emit(OpCodes.Call, typeof(Page).GetProperty("_POST").GetGetMethod());
Also, note that DataSet doesn't have a SetData method - if that's an extension method, you need to use the real type where it's defined rather than DataSet.
i have to use entity framework with dynamic table columns(that user can add column to my table), and i need to have dynamic run-time type entity to map my table.
my scenario :
if DbContext wants to insert static entity(like MyTableEntity) that inherited from DynamicEntity, it will create Dynamic type with same name of entity(like MyTableEntity) with "Dynamic_" prefix, after that create instance from generated runtime type and then fill static type properties value to
instance of runtime object. finally insert method will insert runtime object.
every thing is good and work.
but because TypeBuilder create runtime type and if i call insert two time or more, TypeBuilder will create new type with same name like "Dynamic_MyTableEntity" and DbContext cannot recognize witch class must insert and it is natural.
my question :
how can i remove old type that i create by TypeBuilder or renew or update old type, like first remove all properties and again add all properties.
i create class that inherited from DynamicObject, and i will inherit my dynamic entities from DynamicEntity class.
public class DynamicEntity : System.Dynamic.DynamicObject {
//Runtime Type Prefix
public const string DynamicTypePrefix = "Dynamic_";
//Dictionary Key = PropertyName, Value = Value Of Property
private Dictionary<string, object> properties = new Dictionary<string, object>();
//Dictionary Key = typeof static type, Value = Dynamic Type, Corresponding static type
private static Dictionary<Type, Type> staticType_DynamicType = new Dictionary<Type, Type>();
private static Assembly currentAssembly;
private Assembly CurrentAssembly {
get {
if (currentAssembly == null) {
currentAssembly = Assembly.GetAssembly(type);
}
return currentAssembly;
}
}
//Generate dynamic type from static type, and Cache it to staticType_DynamicType for later use, and return
public Type GetDynamicType() {
Type dynamicType;
if (!staticType_DynamicType.TryGetValue(type, out dynamicType)) {
TypeBuilder typeBuilder = CreateTypeBuilder(CurrentAssembly.FullName, CurrentAssembly.GetLoadedModules()[0].Name, DynamicTypePrefix + type.Name);
foreach (var item in properties.Where(q => q.Value != null).Select(q => new { Name = q.Key, Type = q.Value.GetType() })) {
CreateAutoImplementedProperty(typeBuilder, item.Name, item.Type);
}
dynamicType = typeBuilder.CreateType();
staticType_DynamicType[type] = dynamicType;
}
return dynamicType;
}
//Create TypeBuilder
private TypeBuilder CreateTypeBuilder(string assemblyName, string moduleName, string typeName) {
TypeBuilder typeBuilder = AppDomain
.CurrentDomain
.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run)
.DefineDynamicModule(moduleName)
.DefineType(typeName, TypeAttributes.Public, type);
typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
return typeBuilder;
}
//Create Property for TypeBuilder
private static void CreateAutoImplementedProperty(
TypeBuilder builder, string propertyName, Type propertyType) {
const string PrivateFieldPrefix = "m_";
const string GetterPrefix = "get_";
const string SetterPrefix = "set_";
// Generate the field.
FieldBuilder fieldBuilder = builder.DefineField(
string.Concat(PrivateFieldPrefix, propertyName),
propertyType, FieldAttributes.Private);
// Generate the property
PropertyBuilder propertyBuilder = builder.DefineProperty(
propertyName, System.Reflection.PropertyAttributes.HasDefault, propertyType, null);
// Property getter and setter attributes.
MethodAttributes propertyMethodAttributes =
MethodAttributes.Public | MethodAttributes.SpecialName |
MethodAttributes.HideBySig;
// Define the getter method.
MethodBuilder getterMethod = builder.DefineMethod(
string.Concat(GetterPrefix, propertyName),
propertyMethodAttributes, propertyType, Type.EmptyTypes);
// Emit the IL code.
// ldarg.0
// ldfld,_field
// ret
ILGenerator getterILCode = getterMethod.GetILGenerator();
getterILCode.Emit(OpCodes.Ldarg_0);
getterILCode.Emit(OpCodes.Ldfld, fieldBuilder);
getterILCode.Emit(OpCodes.Ret);
// Define the setter method.
MethodBuilder setterMethod = builder.DefineMethod(
string.Concat(SetterPrefix, propertyName),
propertyMethodAttributes, null, new Type[] { propertyType });
// Emit the IL code.
// ldarg.0
// ldarg.1
// stfld,_field
// ret
ILGenerator setterILCode = setterMethod.GetILGenerator();
setterILCode.Emit(OpCodes.Ldarg_0);
setterILCode.Emit(OpCodes.Ldarg_1);
setterILCode.Emit(OpCodes.Stfld, fieldBuilder);
setterILCode.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getterMethod);
propertyBuilder.SetSetMethod(setterMethod);
}
//Create new instance from runtime type and initialize properties with static type
public object CreateDynamicInstance() {
Type dynamicType = GetDynamicType();
object instance = Activator.CreateInstance(dynamicType);
foreach (var item in type.GetProperties()) {
dynamicType.GetProperty(item.Name).SetValue(instance, item.GetValue(this, null), null);
}
foreach (var item in properties) {
dynamicType.GetProperty(item.Key).SetValue(instance, item.Value, null);
}
return instance;
}
//Static type
private Type type;
public DynamicEntity() {
type = this.GetType();
}
//Set Dynamic Property to static type
public void SetMember(string name, object value) {
lock (this) {
properties[name] = value;
if (staticType_DynamicType.ContainsKey(type)) {
staticType_DynamicType.Remove(type);
}
}
}
public override bool TrySetMember(SetMemberBinder binder, object value) {
SetMember(binder.Name, value);
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
lock (this) {
result = properties[binder.Name];
}
return true;
}
}
sample my entity :
public class MyTableEntity : DynamicEntity {
[Key]
public int ID { get; set; }
}
sample use :
dynamic entity = new MyTableEntity();
entity.SetMember("MyNewColumn", "this is value of column"); //or entity.MyNewColumn = "this is value of column";
myDbContext.Set(entity.GetDynamicType()).Add(entity.CreateDynamicInstance());
myDbContext.SaveChanges();
finally i change my dbcontext and my problem solved
public class HREntities : DbContext {
public HREntities(string connectionString)
: base(connectionString) {
}
public HREntities(string connectionString, Type entityType)
: base(connectionString, GenerateDbCompiledModel(connectionString, entityType)) {
}
private static DbCompiledModel GenerateDbCompiledModel(string connectionString, Type entityType) {
string tableName;
if (typeof(DynamicEntity).IsAssignableFrom(entityType)) {
tableName = entityType.Name.Substring((DynamicEntity.DynamicTypePrefix + "tbl").Length);
}
else {
tableName = entityType.Name.Substring("tbl".Length);
}
DbModelBuilder dbModelBuilder = new DbModelBuilder(DbModelBuilderVersion.Latest);
var entityMethod = dbModelBuilder.GetType().GetMethod("Entity").MakeGenericMethod(entityType);
var entityTypeConfiguration = entityMethod.Invoke(dbModelBuilder, new object[0]);
entityTypeConfiguration.GetType().GetMethod("ToTable", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(string) }, null).Invoke(entityTypeConfiguration, new object[] { tableName });
return dbModelBuilder.Build(new SqlConnection(connectionString)).Compile();
}
}
every time when i want create instance of HREntities i pass my dynamic type and my dbcontext work fine...
First, and to make things clearer I'll explain my scenario from the top:
I have a method which has the following signature:
public virtual void SendEmail(String from, List<String> recepients, Object model)
What I want to do is generate an anonymous object which has the properties of the model object along with the first two parameters as well. Flattening the model object into a PropertyInfo[] is very straightforward. Accordingly, I thought of creating a Dictionary which would hold the PropertyInfo's and the first two params, and then be converted into the anonymous object where the key is the name of the property and the value is the actual value of the property.
Is that possible? Any other suggestions?
If you really want to convert the dictionary to an object that has the items of the dictionary as properties, you can use ExpandoObject:
var dict = new Dictionary<string, object> { { "Property", "foo" } };
var eo = new ExpandoObject();
var eoColl = (ICollection<KeyValuePair<string, object>>)eo;
foreach (var kvp in dict)
{
eoColl.Add(kvp);
}
dynamic eoDynamic = eo;
string value = eoDynamic.Property;
I tried to do this in one statement with a reduce function (Aggregate in Linq). The code below does the same as the accepted answer:
var dict = new Dictionary<string, object> { { "Property", "foo" } };
dynamic eo = dict.Aggregate(new ExpandoObject() as IDictionary<string, Object>,
(a, p) => { a.Add(p); return a; });
string value = eo.Property;
If you want to convert Dictionary<string, object> To Anonymous System.Object. You can use this method:
public static object FromDictToAnonymousObj<TValue>(IDictionary<string, TValue> dict)
{
var types = new Type[dict.Count];
for (int i = 0; i < types.Length; i++)
{
types[i] = typeof(TValue);
}
// dictionaries don't have an order, so we force an order based
// on the Key
var ordered = dict.OrderBy(x => x.Key).ToArray();
string[] names = Array.ConvertAll(ordered, x => x.Key);
Type type = AnonymousType.CreateType(types, names);
object[] values = Array.ConvertAll(ordered, x => (object)x.Value);
object obj = type.GetConstructor(types).Invoke(values);
return obj;
}
like this:
var dict = new Dictionary<string, string>
{
{"Id", "1"},
{"Title", "My title"},
{"Description", "Blah blah blah"},
};
object obj1 = FromDictToAnonymousObj(dict);
to obtain your object.
Where AnonymousType class code is:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
/// <summary>
/// The code generated should be nearly equal to the one generated by
/// csc 12.0.31101.0 when compiling with /optimize+ /debug-. The main
/// difference is in the GetHashCode() (the base init_hash used is
/// compiler-dependant) and in the maxstack of the generated methods.
/// Note that Roslyn (at least the one present at
/// tryroslyn.azurewebsites.net) generates different code for anonymous
/// types.
/// </summary>
public static class AnonymousType
{
private static readonly ConcurrentDictionary<string, Type> GeneratedTypes = new ConcurrentDictionary<string, Type>();
private static readonly AssemblyBuilder AssemblyBuilder;
private static readonly ModuleBuilder ModuleBuilder;
private static readonly string FileName;
// Some objects we cache
private static readonly CustomAttributeBuilder CompilerGeneratedAttributeBuilder = new CustomAttributeBuilder(typeof(CompilerGeneratedAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
private static readonly CustomAttributeBuilder DebuggerBrowsableAttributeBuilder = new CustomAttributeBuilder(typeof(DebuggerBrowsableAttribute).GetConstructor(new[] { typeof(DebuggerBrowsableState) }), new object[] { DebuggerBrowsableState.Never });
private static readonly CustomAttributeBuilder DebuggerHiddenAttributeBuilder = new CustomAttributeBuilder(typeof(DebuggerHiddenAttribute).GetConstructor(Type.EmptyTypes), new object[0]);
private static readonly ConstructorInfo ObjectCtor = typeof(object).GetConstructor(Type.EmptyTypes);
private static readonly MethodInfo ObjectToString = typeof(object).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
private static readonly ConstructorInfo StringBuilderCtor = typeof(StringBuilder).GetConstructor(Type.EmptyTypes);
private static readonly MethodInfo StringBuilderAppendString = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, null);
private static readonly MethodInfo StringBuilderAppendObject = typeof(StringBuilder).GetMethod("Append", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(object) }, null);
private static readonly Type EqualityComparer = typeof(EqualityComparer<>);
private static readonly Type EqualityComparerGenericArgument = EqualityComparer.GetGenericArguments()[0];
private static readonly MethodInfo EqualityComparerDefault = EqualityComparer.GetMethod("get_Default", BindingFlags.Static | BindingFlags.Public, null, Type.EmptyTypes, null);
private static readonly MethodInfo EqualityComparerEquals = EqualityComparer.GetMethod("Equals", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument, EqualityComparerGenericArgument }, null);
private static readonly MethodInfo EqualityComparerGetHashCode = EqualityComparer.GetMethod("GetHashCode", BindingFlags.Instance | BindingFlags.Public, null, new[] { EqualityComparerGenericArgument }, null);
private static int Index = -1;
static AnonymousType()
{
var assemblyName = new AssemblyName("AnonymousTypes");
FileName = assemblyName.Name + ".dll";
AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder = AssemblyBuilder.DefineDynamicModule("AnonymousTypes", FileName);
}
public static void Dump()
{
AssemblyBuilder.Save(FileName);
}
/// <summary>
///
/// </summary>
/// <param name="types"></param>
/// <param name="names"></param>
/// <returns></returns>
public static Type CreateType(Type[] types, string[] names)
{
if (types == null)
{
throw new ArgumentNullException("types");
}
if (names == null)
{
throw new ArgumentNullException("names");
}
if (types.Length != names.Length)
{
throw new ArgumentException("names");
}
// Anonymous classes are generics based. The generic classes
// are distinguished by number of parameters and name of
// parameters. The specific types of the parameters are the
// generic arguments. We recreate this by creating a fullName
// composed of all the property names, separated by a "|"
string fullName = string.Join("|", names.Select(x => Escape(x)));
Type type;
if (!GeneratedTypes.TryGetValue(fullName, out type))
{
// We create only a single class at a time, through this lock
// Note that this is a variant of the double-checked locking.
// It is safe because we are using a thread safe class.
lock (GeneratedTypes)
{
if (!GeneratedTypes.TryGetValue(fullName, out type))
{
int index = Interlocked.Increment(ref Index);
string name = names.Length != 0 ? string.Format("<>f__AnonymousType{0}`{1}", index, names.Length) : string.Format("<>f__AnonymousType{0}", index);
TypeBuilder tb = ModuleBuilder.DefineType(name, TypeAttributes.AnsiClass | TypeAttributes.Class | TypeAttributes.AutoLayout | TypeAttributes.NotPublic | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit);
tb.SetCustomAttribute(CompilerGeneratedAttributeBuilder);
GenericTypeParameterBuilder[] generics = null;
if (names.Length != 0)
{
string[] genericNames = Array.ConvertAll(names, x => string.Format("<{0}>j__TPar", x));
generics = tb.DefineGenericParameters(genericNames);
}
else
{
generics = new GenericTypeParameterBuilder[0];
}
// .ctor
ConstructorBuilder constructor = tb.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, generics);
constructor.SetCustomAttribute(DebuggerHiddenAttributeBuilder);
ILGenerator ilgeneratorConstructor = constructor.GetILGenerator();
ilgeneratorConstructor.Emit(OpCodes.Ldarg_0);
ilgeneratorConstructor.Emit(OpCodes.Call, ObjectCtor);
var fields = new FieldBuilder[names.Length];
// There are two for cycles because we want to have
// all the getter methods before all the other
// methods
for (int i = 0; i < names.Length; i++)
{
// field
fields[i] = tb.DefineField(string.Format("<{0}>i__Field", names[i]), generics[i], FieldAttributes.Private | FieldAttributes.InitOnly);
fields[i].SetCustomAttribute(DebuggerBrowsableAttributeBuilder);
// .ctor
constructor.DefineParameter(i + 1, ParameterAttributes.None, names[i]);
ilgeneratorConstructor.Emit(OpCodes.Ldarg_0);
if (i == 0)
{
ilgeneratorConstructor.Emit(OpCodes.Ldarg_1);
}
else if (i == 1)
{
ilgeneratorConstructor.Emit(OpCodes.Ldarg_2);
}
else if (i == 2)
{
ilgeneratorConstructor.Emit(OpCodes.Ldarg_3);
}
else if (i < 255)
{
ilgeneratorConstructor.Emit(OpCodes.Ldarg_S, (byte)(i + 1));
}
else
{
// Ldarg uses a ushort, but the Emit only
// accepts short, so we use a unchecked(...),
// cast to short and let the CLR interpret it
// as ushort
ilgeneratorConstructor.Emit(OpCodes.Ldarg, unchecked((short)(i + 1)));
}
ilgeneratorConstructor.Emit(OpCodes.Stfld, fields[i]);
// getter
MethodBuilder getter = tb.DefineMethod(string.Format("get_{0}", names[i]), MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName, CallingConventions.HasThis, generics[i], Type.EmptyTypes);
ILGenerator ilgeneratorGetter = getter.GetILGenerator();
ilgeneratorGetter.Emit(OpCodes.Ldarg_0);
ilgeneratorGetter.Emit(OpCodes.Ldfld, fields[i]);
ilgeneratorGetter.Emit(OpCodes.Ret);
PropertyBuilder property = tb.DefineProperty(names[i], PropertyAttributes.None, CallingConventions.HasThis, generics[i], Type.EmptyTypes);
property.SetGetMethod(getter);
}
// ToString()
MethodBuilder toString = tb.DefineMethod("ToString", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(string), Type.EmptyTypes);
toString.SetCustomAttribute(DebuggerHiddenAttributeBuilder);
ILGenerator ilgeneratorToString = toString.GetILGenerator();
ilgeneratorToString.DeclareLocal(typeof(StringBuilder));
ilgeneratorToString.Emit(OpCodes.Newobj, StringBuilderCtor);
ilgeneratorToString.Emit(OpCodes.Stloc_0);
// Equals
MethodBuilder equals = tb.DefineMethod("Equals", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(bool), new[] { typeof(object) });
equals.SetCustomAttribute(DebuggerHiddenAttributeBuilder);
equals.DefineParameter(1, ParameterAttributes.None, "value");
ILGenerator ilgeneratorEquals = equals.GetILGenerator();
ilgeneratorEquals.DeclareLocal(tb);
ilgeneratorEquals.Emit(OpCodes.Ldarg_1);
ilgeneratorEquals.Emit(OpCodes.Isinst, tb);
ilgeneratorEquals.Emit(OpCodes.Stloc_0);
ilgeneratorEquals.Emit(OpCodes.Ldloc_0);
Label equalsLabel = ilgeneratorEquals.DefineLabel();
// GetHashCode()
MethodBuilder getHashCode = tb.DefineMethod("GetHashCode", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, CallingConventions.HasThis, typeof(int), Type.EmptyTypes);
getHashCode.SetCustomAttribute(DebuggerHiddenAttributeBuilder);
ILGenerator ilgeneratorGetHashCode = getHashCode.GetILGenerator();
ilgeneratorGetHashCode.DeclareLocal(typeof(int));
if (names.Length == 0)
{
ilgeneratorGetHashCode.Emit(OpCodes.Ldc_I4_0);
}
else
{
// As done by Roslyn
// Note that initHash can vary, because
// string.GetHashCode() isn't "stable" for
// different compilation of the code
int initHash = 0;
for (int i = 0; i < names.Length; i++)
{
initHash = unchecked(initHash * (-1521134295) + fields[i].Name.GetHashCode());
}
// Note that the CSC seems to generate a
// different seed for every anonymous class
ilgeneratorGetHashCode.Emit(OpCodes.Ldc_I4, initHash);
}
for (int i = 0; i < names.Length; i++)
{
// Equals()
Type equalityComparerT = EqualityComparer.MakeGenericType(generics[i]);
MethodInfo equalityComparerTDefault = TypeBuilder.GetMethod(equalityComparerT, EqualityComparerDefault);
MethodInfo equalityComparerTEquals = TypeBuilder.GetMethod(equalityComparerT, EqualityComparerEquals);
ilgeneratorEquals.Emit(OpCodes.Brfalse_S, equalsLabel);
ilgeneratorEquals.Emit(OpCodes.Call, equalityComparerTDefault);
ilgeneratorEquals.Emit(OpCodes.Ldarg_0);
ilgeneratorEquals.Emit(OpCodes.Ldfld, fields[i]);
ilgeneratorEquals.Emit(OpCodes.Ldloc_0);
ilgeneratorEquals.Emit(OpCodes.Ldfld, fields[i]);
ilgeneratorEquals.Emit(OpCodes.Callvirt, equalityComparerTEquals);
// GetHashCode();
MethodInfo EqualityComparerTGetHashCode = TypeBuilder.GetMethod(equalityComparerT, EqualityComparerGetHashCode);
ilgeneratorGetHashCode.Emit(OpCodes.Stloc_0);
ilgeneratorGetHashCode.Emit(OpCodes.Ldc_I4, -1521134295);
ilgeneratorGetHashCode.Emit(OpCodes.Ldloc_0);
ilgeneratorGetHashCode.Emit(OpCodes.Mul);
ilgeneratorGetHashCode.Emit(OpCodes.Call, EqualityComparerDefault);
ilgeneratorGetHashCode.Emit(OpCodes.Ldarg_0);
ilgeneratorGetHashCode.Emit(OpCodes.Ldfld, fields[i]);
ilgeneratorGetHashCode.Emit(OpCodes.Callvirt, EqualityComparerGetHashCode);
ilgeneratorGetHashCode.Emit(OpCodes.Add);
// ToString()
ilgeneratorToString.Emit(OpCodes.Ldloc_0);
ilgeneratorToString.Emit(OpCodes.Ldstr, i == 0 ? string.Format("{{ {0} = ", names[i]) : string.Format(", {0} = ", names[i]));
ilgeneratorToString.Emit(OpCodes.Callvirt, StringBuilderAppendString);
ilgeneratorToString.Emit(OpCodes.Pop);
ilgeneratorToString.Emit(OpCodes.Ldloc_0);
ilgeneratorToString.Emit(OpCodes.Ldarg_0);
ilgeneratorToString.Emit(OpCodes.Ldfld, fields[i]);
ilgeneratorToString.Emit(OpCodes.Box, generics[i]);
ilgeneratorToString.Emit(OpCodes.Callvirt, StringBuilderAppendObject);
ilgeneratorToString.Emit(OpCodes.Pop);
}
// .ctor
ilgeneratorConstructor.Emit(OpCodes.Ret);
// Equals()
if (names.Length == 0)
{
ilgeneratorEquals.Emit(OpCodes.Ldnull);
ilgeneratorEquals.Emit(OpCodes.Ceq);
ilgeneratorEquals.Emit(OpCodes.Ldc_I4_0);
ilgeneratorEquals.Emit(OpCodes.Ceq);
}
else
{
ilgeneratorEquals.Emit(OpCodes.Ret);
ilgeneratorEquals.MarkLabel(equalsLabel);
ilgeneratorEquals.Emit(OpCodes.Ldc_I4_0);
}
ilgeneratorEquals.Emit(OpCodes.Ret);
// GetHashCode()
ilgeneratorGetHashCode.Emit(OpCodes.Stloc_0);
ilgeneratorGetHashCode.Emit(OpCodes.Ldloc_0);
ilgeneratorGetHashCode.Emit(OpCodes.Ret);
// ToString()
ilgeneratorToString.Emit(OpCodes.Ldloc_0);
ilgeneratorToString.Emit(OpCodes.Ldstr, names.Length == 0 ? "{ }" : " }");
ilgeneratorToString.Emit(OpCodes.Callvirt, StringBuilderAppendString);
ilgeneratorToString.Emit(OpCodes.Pop);
ilgeneratorToString.Emit(OpCodes.Ldloc_0);
ilgeneratorToString.Emit(OpCodes.Callvirt, ObjectToString);
ilgeneratorToString.Emit(OpCodes.Ret);
type = tb.CreateType();
type = GeneratedTypes.GetOrAdd(fullName, type);
}
}
}
if (types.Length != 0)
{
type = type.MakeGenericType(types);
}
return type;
}
private static string Escape(string str)
{
// We escape the \ with \\, so that we can safely escape the
// "|" (that we use as a separator) with "\|"
str = str.Replace(#"\", #"\\");
str = str.Replace(#"|", #"\|");
return str;
}
}
Reference: https://stackoverflow.com/a/29428640/2073920
If you have a class you want to covert the dictionary too, you can use the following to convert a dictionary to an object of that class:
Example class:
public class Properties1
{
public string Property { get; set; }
}
The solution:
JavaScriptSerializer serializer = new JavaScriptSerializer();
Dictionary<string, object> dict = new Dictionary<string, object> { { "Property", "foo" } };
Properties1 properties = serializer.ConvertToType<Properties1>(dict);
string value = properties.Property;
You could also use a method like this to build the object from the dictionary, obviously this also requires you to have a class.
private static T DictionaryToObject<T>(IDictionary<string, object> dict) where T : new()
{
T t = new T();
PropertyInfo[] properties = t.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
if (!dict.Any(x => x.Key.Equals(property.Name,
StringComparison.InvariantCultureIgnoreCase)))
continue;
KeyValuePair<string, object> item = dict.First(x => x.Key.Equals(property.Name,
StringComparison.InvariantCultureIgnoreCase));
Type tPropertyType = t.GetType().GetProperty(property.Name).PropertyType;
Type newT = Nullable.GetUnderlyingType(tPropertyType) ?? tPropertyType;
object newA = Convert.ChangeType(item.Value, newT);
t.GetType().GetProperty(property.Name).SetValue(t, newA, null);
}
return t;
}
However if you do not have the class you can create a dynamic object from a dictionary like this:
private static dynamic DictionaryToObject(Dictionary<string, object> dict)
{
IDictionary<string, object> eo = (IDictionary<string, object>)new ExpandoObject();
foreach (KeyValuePair<string, object> kvp in dict)
{
eo.Add(kvp);
}
return eo;
}
You can use it like this:
Dictionary<string, object> dict = new Dictionary<string, object> {{ "Property", "foo" }};
dynamic properties = DictionaryToObject(dict);
string value = properties.Property;
Slightly more modular version of svick's answer, using a couple extension methods:
public static class Extensions
{
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> items)
{
foreach (var item in items)
{
collection.Add(item);
}
}
public static dynamic ToDynamicObject(this IDictionary<string, object> source)
{
ICollection<KeyValuePair<string, object>> someObject = new ExpandoObject();
someObject.AddRange(source);
return someObject;
}
}
The code below handles sub-dictionaries and converts them to nested dynamic objects as well:
[return: NotNullIfNotNull(nameof(dictionary))]
static dynamic? ToDynamic(IReadOnlyDictionary<string, object?>? dictionary) =>
dictionary?.Aggregate(
(IDictionary<string, object?>)new ExpandoObject(),
(obj, i) =>
{
if (i.Value is IReadOnlyDictionary<string, object?> nestedDictionary)
obj.Add(new(i.Key, ToDynamic(nestedDictionary)));
else
obj.Add(i);
return obj;
});
This approach allows you to access the contents of nested dictionaries just by accessing the dynamic object itself:
var record = ToDynamic(...);
string cityName = record.city.name;
Anonymous objects are one that generated for you by compiler. You cannot generate dynamically create one. On the other hand you can emit such object, but I really do not think this is good idea.
May be you can try dynamic objects? The result will be an object with all properties you need.
The credit here goes to the accepted answer. Adding this because I wanted to turn a List< Dictionary< string,object >> into a List< dynamic>. The purpose is for pulling records from a database table. Here is what I did.
public static List<dynamic> ListDictionaryToListDynamic(List<Dictionary<string,object>> dbRecords)
{
var eRecords = new List<dynamic>();
foreach (var record in dbRecords)
{
var eRecord = new ExpandoObject() as IDictionary<string, object>;
foreach (var kvp in record)
{
eRecord.Add(kvp);
}
eRecords.Add(eRecord);
}
return eRecords;
}