如何正确继承元组,以便从 orleans 生成序列化程序是正确的?
How to properly inherit from tuples so that serializer generation from orleans is correct?
我有一个使用 netstandard2.0 作为 TargetFramework 并遵循 Nuget 包的项目:
microsoft.orleans.core -> 版本="2.2.0"
microsoft.orleans.orleanscodegenerator.build -> 版本="2.2.0"
这个项目有一个实现元组的 DTO,如下所示:
public sealed class SomeDetailsDto : Tuple<Guid, Guid>
{
public SomeDetailsDto(Guid firstGuidId, Guid secondGuidId)
: base(firstGuidId, secondGuidId)
{
}
public Guid firstGuidId => Item1;
public Guid secondGuidId => Item2;
}
此 DTO 将在 grain 方法中使用。 orleans 生成的序列化程序代码如下所示:
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(@"Orleans-CodeGenerator", @"2.0.0.0"), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute, global::Orleans.CodeGeneration.SerializerAttribute(typeof(global::SomeDetailsDto))]
internal sealed class OrleansCodeGenSomeDetailsDtoSerializer
{
private readonly global::System.Func<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid> getField0;
private readonly global::System.Action<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid> setField0;
private readonly global::System.Func<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid> getField1;
private readonly global::System.Action<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid> setField1;
public OrleansCodeGenSomeDetailsDtoSerializer(global::Orleans.Serialization.IFieldUtils fieldUtils)
{
global::System.Reflection.FieldInfo field0 = typeof(global::System.Tuple<global::System.Guid, global::System.Guid>).GetField(@"m_Item1", (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public));
getField0 = (global::System.Func<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid>)fieldUtils.GetGetter(field0);
setField0 = (global::System.Action<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid>)fieldUtils.GetReferenceSetter(field0);
global::System.Reflection.FieldInfo field1 = typeof(global::System.Tuple<global::System.Guid, global::System.Guid>).GetField(@"m_Item2", (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public));
getField1 = (global::System.Func<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid>)fieldUtils.GetGetter(field1);
setField1 = (global::System.Action<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid>)fieldUtils.GetReferenceSetter(field1);
}
[global::Orleans.CodeGeneration.CopierMethodAttribute]
public global::System.Object DeepCopier(global::System.Object original, global::Orleans.Serialization.ICopyContext context)
{
global::SomeDetailsDto input = ((global::SomeDetailsDto)original);
global::SomeDetailsDto result = (global::SomeDetailsDto)global::System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(global::SomeDetailsDto));
context.RecordCopy(original, result);
setField0(result, getField0(input));
setField1(result, getField1(input));
return result;
}
[global::Orleans.CodeGeneration.SerializerMethodAttribute]
public void Serializer(global::System.Object untypedInput, global::Orleans.Serialization.ISerializationContext context, global::System.Type expected)
{
global::SomeDetailsDto input = (global::SomeDetailsDto)untypedInput;
context.SerializeInner(getField0(input), typeof(global::System.Guid));
context.SerializeInner(getField1(input), typeof(global::System.Guid));
}
[global::Orleans.CodeGeneration.DeserializerMethodAttribute]
public global::System.Object Deserializer(global::System.Type expected, global::Orleans.Serialization.IDeserializationContext context)
{
global::SomeDetailsDto result = (global::SomeDetailsDto)global::System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(global::SomeDetailsDto));
context.RecordObject(result);
setField0(result, (global::System.Guid)context.DeserializeInner(typeof(global::System.Guid)));
setField1(result, (global::System.Guid)context.DeserializeInner(typeof(global::System.Guid)));
return (global::SomeDetailsDto)result;
}
}
一切都很好。
但最近我将 TargetFramework 更新为 netstandard2.1,microsoft.orleans.core 更新为“3.0.2”,而不是 microsoft.orleans.orleanscodegenerator.build (2.2.0 ),我安装了 Microsoft.Orleans.CodeGenerator.MSBuild (3.0.2)。
通过上述设置,我收到以下警告:
警告 ORL1001:类型 SomeDetailsDto 具有属于引用程序集的基类型。此类型的序列化程序生成可能不包含重要的基本类型字段。
恢复、构建和发布命令都在工作。但是,生成的序列化程序有问题,因为测试失败。
下面是奥尔良为同一个 DTO
生成的代码
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "2.0.0.0"), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute, global::Orleans.CodeGeneration.SerializerAttribute(typeof(global::SomeDetailsDto))]
internal sealed class OrleansCodeGenSomeDetailsDtoSerializer
{
public OrleansCodeGenSomeDetailsDtoSerializer(global::Orleans.Serialization.IFieldUtils fieldUtils)
{
}
[global::Orleans.CodeGeneration.CopierMethodAttribute]
public object DeepCopier(object original, global::Orleans.Serialization.ICopyContext context)
{
global::SomeDetailsDto input = ((global::SomeDetailsDto)original);
global::SomeDetailsDto result = (global::SomeDetailsDto)global::System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(global::SomeDetailsDto));
context.RecordCopy(original, result);
return result;
}
[global::Orleans.CodeGeneration.SerializerMethodAttribute]
public void Serializer(object untypedInput, global::Orleans.Serialization.ISerializationContext context, global::System.Type expected)
{
global::SomeDetailsDto input = (global::SomeDetailsDto)untypedInput;
}
[global::Orleans.CodeGeneration.DeserializerMethodAttribute]
public object Deserializer(global::System.Type expected, global::Orleans.Serialization.IDeserializationContext context)
{
global::SomeDetailsDto result = (global::SomeDetailsDto)global::System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(global::SomeDetailsDto));
context.RecordObject(result);
return (global::SomeDetailsDto)result;
}
}
最新的序列化程序忽略了警告中提到的元组的 Item1 和 Item2。我在这个问题上搜索了很多,但没有找到任何东西。我可以使用 this orleans 文档中提到的自定义序列化程序。但是我有另一个 DTO,它也收到了前面提到的警告。
解决此问题的更好方法是什么?
我建议不要继承自Tuple
。相反,将这些字段放在 class 上,这样 class 看起来像这样:
[Serializable]
public sealed class SomeDetailsDto
{
public SomeDetailsDto(Guid firstGuidId, Guid secondGuidId)
{
FirstGuidId = firstGuidId;
SecondGuidId = secondGuidId;
}
public Guid FirstGuidId { get; }
public Guid SecondGuidId { get; }
}
请注意,我还向您的 class 添加了 [Serializable]
属性。我还建议您始终将 [Serializable]
添加到您打算序列化的类型。代码生成器将尽最大努力推断你想要为该类型生成一个序列化程序(因为它出现在 grain 接口方法签名和其他启发式方法中),但该过程不能完全准确 - 所以最好是明确的.
如果你想要一些通用类型表明你的 class 有 2 个字段(假设这对你有用),那么你可以定义一个接口或你自己的类似元组的类型并在你的 DTO。
正如构建警告消息指出的那样,Tuple
是在称为 ref-only 程序集的特殊类型程序集中定义的。这意味着 Orleans 代码生成器无法看到 Tuple
class 中的任何字段(那些仅引用程序集省略了私有成员和所有 IL 代码,因此它们不存在于全部)。在不知道基 class 上存在哪些字段的情况下,代码生成器无法为其生成正确的序列化程序。这是由仅引用程序集引起的限制,并且在 Orleans 存储库中已经讨论了如何纠正此限制。
这里有一个支持继承自 Tuple
和集合类型的功能请求:https://github.com/dotnet/orleans/issues/6158
我有一个使用 netstandard2.0 作为 TargetFramework 并遵循 Nuget 包的项目:
microsoft.orleans.core -> 版本="2.2.0"
microsoft.orleans.orleanscodegenerator.build -> 版本="2.2.0"
这个项目有一个实现元组的 DTO,如下所示:
public sealed class SomeDetailsDto : Tuple<Guid, Guid>
{
public SomeDetailsDto(Guid firstGuidId, Guid secondGuidId)
: base(firstGuidId, secondGuidId)
{
}
public Guid firstGuidId => Item1;
public Guid secondGuidId => Item2;
}
此 DTO 将在 grain 方法中使用。 orleans 生成的序列化程序代码如下所示:
[global::System.CodeDom.Compiler.GeneratedCodeAttribute(@"Orleans-CodeGenerator", @"2.0.0.0"), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute, global::Orleans.CodeGeneration.SerializerAttribute(typeof(global::SomeDetailsDto))]
internal sealed class OrleansCodeGenSomeDetailsDtoSerializer
{
private readonly global::System.Func<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid> getField0;
private readonly global::System.Action<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid> setField0;
private readonly global::System.Func<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid> getField1;
private readonly global::System.Action<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid> setField1;
public OrleansCodeGenSomeDetailsDtoSerializer(global::Orleans.Serialization.IFieldUtils fieldUtils)
{
global::System.Reflection.FieldInfo field0 = typeof(global::System.Tuple<global::System.Guid, global::System.Guid>).GetField(@"m_Item1", (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public));
getField0 = (global::System.Func<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid>)fieldUtils.GetGetter(field0);
setField0 = (global::System.Action<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid>)fieldUtils.GetReferenceSetter(field0);
global::System.Reflection.FieldInfo field1 = typeof(global::System.Tuple<global::System.Guid, global::System.Guid>).GetField(@"m_Item2", (System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public));
getField1 = (global::System.Func<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid>)fieldUtils.GetGetter(field1);
setField1 = (global::System.Action<global::System.Tuple<global::System.Guid, global::System.Guid>, global::System.Guid>)fieldUtils.GetReferenceSetter(field1);
}
[global::Orleans.CodeGeneration.CopierMethodAttribute]
public global::System.Object DeepCopier(global::System.Object original, global::Orleans.Serialization.ICopyContext context)
{
global::SomeDetailsDto input = ((global::SomeDetailsDto)original);
global::SomeDetailsDto result = (global::SomeDetailsDto)global::System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(global::SomeDetailsDto));
context.RecordCopy(original, result);
setField0(result, getField0(input));
setField1(result, getField1(input));
return result;
}
[global::Orleans.CodeGeneration.SerializerMethodAttribute]
public void Serializer(global::System.Object untypedInput, global::Orleans.Serialization.ISerializationContext context, global::System.Type expected)
{
global::SomeDetailsDto input = (global::SomeDetailsDto)untypedInput;
context.SerializeInner(getField0(input), typeof(global::System.Guid));
context.SerializeInner(getField1(input), typeof(global::System.Guid));
}
[global::Orleans.CodeGeneration.DeserializerMethodAttribute]
public global::System.Object Deserializer(global::System.Type expected, global::Orleans.Serialization.IDeserializationContext context)
{
global::SomeDetailsDto result = (global::SomeDetailsDto)global::System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(global::SomeDetailsDto));
context.RecordObject(result);
setField0(result, (global::System.Guid)context.DeserializeInner(typeof(global::System.Guid)));
setField1(result, (global::System.Guid)context.DeserializeInner(typeof(global::System.Guid)));
return (global::SomeDetailsDto)result;
}
}
一切都很好。
但最近我将 TargetFramework 更新为 netstandard2.1,microsoft.orleans.core 更新为“3.0.2”,而不是 microsoft.orleans.orleanscodegenerator.build (2.2.0 ),我安装了 Microsoft.Orleans.CodeGenerator.MSBuild (3.0.2)。
通过上述设置,我收到以下警告:
警告 ORL1001:类型 SomeDetailsDto 具有属于引用程序集的基类型。此类型的序列化程序生成可能不包含重要的基本类型字段。
恢复、构建和发布命令都在工作。但是,生成的序列化程序有问题,因为测试失败。
下面是奥尔良为同一个 DTO
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("OrleansCodeGen", "2.0.0.0"), global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute, global::Orleans.CodeGeneration.SerializerAttribute(typeof(global::SomeDetailsDto))]
internal sealed class OrleansCodeGenSomeDetailsDtoSerializer
{
public OrleansCodeGenSomeDetailsDtoSerializer(global::Orleans.Serialization.IFieldUtils fieldUtils)
{
}
[global::Orleans.CodeGeneration.CopierMethodAttribute]
public object DeepCopier(object original, global::Orleans.Serialization.ICopyContext context)
{
global::SomeDetailsDto input = ((global::SomeDetailsDto)original);
global::SomeDetailsDto result = (global::SomeDetailsDto)global::System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(global::SomeDetailsDto));
context.RecordCopy(original, result);
return result;
}
[global::Orleans.CodeGeneration.SerializerMethodAttribute]
public void Serializer(object untypedInput, global::Orleans.Serialization.ISerializationContext context, global::System.Type expected)
{
global::SomeDetailsDto input = (global::SomeDetailsDto)untypedInput;
}
[global::Orleans.CodeGeneration.DeserializerMethodAttribute]
public object Deserializer(global::System.Type expected, global::Orleans.Serialization.IDeserializationContext context)
{
global::SomeDetailsDto result = (global::SomeDetailsDto)global::System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(global::SomeDetailsDto));
context.RecordObject(result);
return (global::SomeDetailsDto)result;
}
}
最新的序列化程序忽略了警告中提到的元组的 Item1 和 Item2。我在这个问题上搜索了很多,但没有找到任何东西。我可以使用 this orleans 文档中提到的自定义序列化程序。但是我有另一个 DTO,它也收到了前面提到的警告。
解决此问题的更好方法是什么?
我建议不要继承自Tuple
。相反,将这些字段放在 class 上,这样 class 看起来像这样:
[Serializable]
public sealed class SomeDetailsDto
{
public SomeDetailsDto(Guid firstGuidId, Guid secondGuidId)
{
FirstGuidId = firstGuidId;
SecondGuidId = secondGuidId;
}
public Guid FirstGuidId { get; }
public Guid SecondGuidId { get; }
}
请注意,我还向您的 class 添加了 [Serializable]
属性。我还建议您始终将 [Serializable]
添加到您打算序列化的类型。代码生成器将尽最大努力推断你想要为该类型生成一个序列化程序(因为它出现在 grain 接口方法签名和其他启发式方法中),但该过程不能完全准确 - 所以最好是明确的.
如果你想要一些通用类型表明你的 class 有 2 个字段(假设这对你有用),那么你可以定义一个接口或你自己的类似元组的类型并在你的 DTO。
正如构建警告消息指出的那样,Tuple
是在称为 ref-only 程序集的特殊类型程序集中定义的。这意味着 Orleans 代码生成器无法看到 Tuple
class 中的任何字段(那些仅引用程序集省略了私有成员和所有 IL 代码,因此它们不存在于全部)。在不知道基 class 上存在哪些字段的情况下,代码生成器无法为其生成正确的序列化程序。这是由仅引用程序集引起的限制,并且在 Orleans 存储库中已经讨论了如何纠正此限制。
这里有一个支持继承自 Tuple
和集合类型的功能请求:https://github.com/dotnet/orleans/issues/6158