我有一个类“预测”:
public class Forecast
{
public int Id { get; set; }
public int Description{ get; set; }
}
在某些情况下,我为类Forecast添加新字段取决于参数sing反射。因此,返回的对象可能如下所示:
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",
}}
正如你所看到的,在4个场景中有动态字段。我如何将其转换为类预测?
**更新:**在运行时创建新字段
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);
}
}
然后我用这个生成字段,作为Int(nbForecast=4)的输入
var fields = GenerateFields(nbForecast);
当我创建新对象时,变量newObjectForecast= MyObjectBuilderApi.创建新对象(字段,类型(预测).名称,类型(预测));
所以最后我把字段分配给了我的对象,我的问题是如何从后端链接到返回的json?
1条答案
按热度按时间qlzsbp2j1#
您可以使用JSON.Net提供的JsonExtensionDataAttribute
类
也可以将额外的属性放在列表中
更新
你不需要任何反射来添加一个条目,只需将其添加到字典中即可.
但如果你想用更难的方法,用反射
但这和你问题中的json标签无关,它需要一个特殊的帖子。但我不认为你找到了答案,因为它根本没有任何意义。你不能在代码中使用forecast.Extra[“fci”]或forecast.fci,因为你不知道json包含什么属性。