Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
public static Type CreateType(this IDictionary<string, PropertySchema> properties, string typeName)
{
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run);
ModuleBuilder module = assemblyBuilder.DefineDynamicModule("tmp");
TypeBuilder typeBuilder = module.DefineType(typeName, TypeAttributes.Public | TypeAttributes.Class);
AddAttribute<DataContractAttribute>(typeBuilder);
// Loop over the attributes that will be used as the properties names in out new type
foreach (var prop in properties)
{
string propertyName = prop.Key;
var propType = prop.Value.Type;
if (propType == typeof(TimeSpan)) propType = typeof(DateTime);//timespan is not supported by avro core lib
// Generate a private field
FieldBuilder field = typeBuilder.DefineField("_" + propertyName, propType, FieldAttributes.Private);
// Generate a public property
PropertyBuilder property =
typeBuilder.DefineProperty(propertyName,
PropertyAttributes.None,
propType,
new Type[] { propType });
if (prop.Value.IsNullable) {
AddAttribute<NullableSchemaAttribute>(property);
}
AddAttribute<DataMemberAttribute>(property);
MethodAttributes GetSetAttr =
MethodAttributes.Public |
MethodAttributes.HideBySig;
MethodBuilder currGetPropMthdBldr =
typeBuilder.DefineMethod("get_value",
GetSetAttr,
propType,
Type.EmptyTypes);
ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
currGetIL.Emit(OpCodes.Ldarg_0);
currGetIL.Emit(OpCodes.Ldfld, field);
currGetIL.Emit(OpCodes.Ret);
MethodBuilder currSetPropMthdBldr =
typeBuilder.DefineMethod("set_value",
GetSetAttr,
null,
new Type[] { propType });
ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
currSetIL.Emit(OpCodes.Ldarg_0);
currSetIL.Emit(OpCodes.Ldarg_1);
currSetIL.Emit(OpCodes.Stfld, field);
currSetIL.Emit(OpCodes.Ret);
property.SetGetMethod(currGetPropMthdBldr);
property.SetSetMethod(currSetPropMthdBldr);
}
return typeBuilder.CreateType();
}
Зачем этот огород, если есть ExpandoObject и dynamic?
const string Schema = @"{
""type"":""record"",
""name"":""Microsoft.Hadoop.Avro.Specifications.SensorData"",
""fields"":
[
{
""name"":""Location"",
""type"":
{
""type"":""record"",
""name"":""Microsoft.Hadoop.Avro.Specifications.Location"",
""fields"":
[
{ ""name"":""Floor"", ""type"":""int"" },
{ ""name"":""Room"", ""type"":""int"" }
]
}
},
{ ""name"":""Value"", ""type"":""bytes"" }
]
}";
//Create a generic serializer based on the schema
var serializer = AvroSerializer.CreateGeneric(Schema);
var rootSchema = serializer.WriterSchema as RecordSchema;
//Create a memory stream buffer
using (var stream = new MemoryStream())
{
//Create a generic record to represent the data
dynamic location = new AvroRecord(rootSchema.GetField("Location").TypeSchema);
location.Floor = 1;
location.Room = 243;
dynamic expected = new AvroRecord(serializer.WriterSchema);
expected.Location = location;
expected.Value = new byte[] { 1, 2, 3, 4, 5 };
Console.WriteLine("Serializing Sample Data Set...");
//Serialize the data
serializer.Serialize(stream, expected);
public static class AvroExtensions {
public static string GetAvroSchemaFromType(Type t) {
var m = typeof(AvroExtensions).GetMethod(nameof(GetAvroSchema));
var ctor = m.MakeGenericMethod(new[] { t });
return (string)ctor.Invoke(null, null);
}
public static string GetAvroSchema<T>()
{
var s = AvroSerializer.Create<T>();
return s.WriterSchema.ToString();
}
}
public IEnumerable<T> GetEntities<T>(string table) where T : ITableEntity, new()
{
var table = _tableClient.GetTableReference(table);
var query = table.CreateQuery<T>();
//...
return rows;
}
public static void Copy<T>()
{
var s = Source.Create<T>();
var d = Dest.Create<T>();
foreach (var item in s)
{
Dest.write(item);
}
}
public static void Copy(Type t)
{
var m = typeof(AvroExtensions).GetMethod(nameof(Copy));
var ctor = m.MakeGenericMethod(new[] { t });
return (string)ctor.Invoke(null, null);
}
Когда у меня возникла проблема с десериализацией объектов, нашел где-то:
public sealed class dsreplace : System.Runtime.Serialization.SerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
var outType =
Type.GetType(String.Format("{0}, {1}", typeName, assemblyName), false)
?? Type.GetType(String.Format("{0}, {1}", typeName, assemblyName), false, false)
?? Type.GetType(String.Format("{0}", typeName), false, false));
return outType;
}
}
Но все типы уже предварительно загружены.
Вы не пытались подписаться на AssemblyResolve и переопределить сборку?
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
// ...
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name == "foo")
return typeof(Bar).Assembly;
return null;
}
Еще есть событие TypeResolve, на случай если имена типов разные.
Достоинство этого метода — в том, что имя типа парсится системными средствами.
А оно ведь сломается если layout объектов разный? Т.е. все поля формально есть но в другом порядке или поле добавилось.
.Net Бинарная сериализация без ссылки на сборку с исходным типом или как договориться с BinaryFormatter