当我尝试在.NET Core项目(针对2.2)中的表达式树上打开my custom visualizer时,出现以下异常:
自定义可视化程序组件在调试过程中引发了类型为'System.TypeLoadException'的未处理异常。
无法从程序集'mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089'中加载类型'System.Runtime.CompilerServices.IsReadOnlyAttribute'。
以下代码(从问题末尾的堆栈跟踪中得出)似乎有相同的问题:
// using System;
// using System.IO;
// using System.Runtime.Serialization.Formatters.Binary;
var stream = File.Create(Path.GetTempFileName());
var formatter = new BinaryFormatter();
var data = new VisualizerData(expr); // serialized class with information about a given expression tree
formatter.Serialize(stream, data); // fails with the same exception
当代码在.NET Core项目中运行但使用来自引用的.NET Framework程序集(目标4.7.2)的类(VisualizerData
)时;该程序集引用了WPF程序集。
如何调试此问题?可能是什么原因造成的?
请注意,这里没有进行任何反序列化;这就是开始序列化的全部过程。
堆栈跟踪:
at System.ModuleHandle.ResolveType(RuntimeModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type)
at System.ModuleHandle.ResolveTypeHandleInternal(RuntimeModule module, Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)
at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(CustomAttributeRecord caRecord, MetadataImport scope, Assembly& lastAptcaOkAssembly, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, Object[] attributes, IList derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctor, Boolean& ctorHasParameters, Boolean& isVarArg)
at System.Reflection.CustomAttribute.IsCustomAttributeDefined(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, RuntimeType attributeFilterType, Int32 attributeCtorToken, Boolean mustBeInheritable)
at System.Reflection.CustomAttribute.IsDefined(RuntimeMethodInfo method, RuntimeType caType, Boolean inherit)
at System.Runtime.Serialization.SerializationEvents.GetMethodsWithAttribute(Type attribute, Type t)
at System.Runtime.Serialization.SerializationEvents..ctor(Type t)
at System.Runtime.Serialization.SerializationEventsCache.<>c.<GetSerializationEventsForType>b__1_0(Type type)
at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
at System.Runtime.Serialization.SerializationEventsCache.GetSerializationEventsForType(Type t)
at System.Runtime.Serialization.SerializationObjectManager.RegisterObject(Object obj)
at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArrayMember(WriteObjectInfo objectInfo, NameInfo arrayElemTypeNameInfo, Object data)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteArray(WriteObjectInfo objectInfo, NameInfo memberNameInfo, WriteObjectInfo memberObjectInfo)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, BinaryFormatterWriter serWriter, Boolean fCheck)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Boolean check)
at ExpressionTreeVisualizer.VisualizerDataObjectSource.TransferData(Object target, Stream incomingData, Stream outgoingData) in C:\Users\Spitz\source\repos\zspitz\ExpressionToString\Visualizer.Shared\VisualizerDataObjectSource.cs:line 9
at Microsoft.VisualStudio.DebuggerVisualizers.DebuggeeSide.Impl.ClrCustomVisualizerDebuggeeHost.TransferData(Object visualizedObject, Byte[] uiSideData)
答案 0 :(得分:0)
如您所见,以下消息是指NET Framework 4.0元素:
无法从程序集'mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089'中加载类型'System.Runtime.CompilerServices.IsReadOnlyAttribute'。
您可以使用的最大NetFramework目标由该元素定义。
答案 1 :(得分:0)
看来,序列化在引用的.NET Framework程序集中定义的值类型是问题的根源。
使用以下方法:
static (bool success, string failPath, string errorMessage) CanSerialize(object o, string path = "") {
var formatter = new BinaryFormatter();
using (var stream = File.Create(Path.GetTempFileName())) {
return CanSerialize(o, path, formatter, stream);
}
}
static (bool success, string failPath, string errorMessage) CanSerialize(object o, string path, BinaryFormatter formatter, Stream stream) {
if (o == null) { return (false, path, "Null object"); }
string msg;
var t = o.GetType();
if (t.IsPrimitive || t == typeof(string)) { return (true, path, null); }
try {
formatter.Serialize(stream, o);
return (true, path, null);
} catch (Exception ex) {
msg = ex.Message;
}
List<(string, object)> values;
if (t.IsArray) {
values = (o as IEnumerable).ToObjectList()
.Select((x, index) => ($"[{index}]", x))
.Where(x => x.Item2 != null)
.ToList();
} else {
values = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(fld => !fld.IsStatic)
.Select(fld => ($".{fld.Name}", fld.GetValue(o)))
.Where(x => x.Item2 != null)
.ToList();
}
foreach (var (name, value) in values) {
var ret = CanSerialize(value, path + name, formatter, stream);
if (!ret.success) { return ret; }
}
return (false, path, msg);
}
以下struct
定义:
[Serializable]
public struct EndNodeData {
public string Closure { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public string Value { get; set; }
}
以下代码:
var endnodeData = new EndNodeData {
Closure = null,
Name = null,
Type = "int",
Value = "5"
};
Console.WriteLine(CanSerialize(endnodeData));
打印出:
(False,,无法从程序集'mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089'中加载类型'System.Runtime.CompilerServices.IsReadOnlyAttribute'。)
似乎是这种特定类型或一般的值类型存在问题。