gpt4 book ai didi

c# - 无效操作异常 : The type of the argument object 'Scratch' is not primitive

转载 作者:太空宇宙 更新时间:2023-11-03 10:36:57 25 4
gpt4 key购买 nike

所以有错误。

InvalidOperationException: The type of the argument object 'Scratch' is not primitive

我正在做的是序列化一个类列表 ( List<BaseEnemy> )。 BaseEnemy 类也有一个类列表 ( List<BaseMoves> )。当我运行时,BaseEnemy 列表会正确序列化。但是,BaseMoves 列表没有。 Scratch是一个派生自存储在 List<BaseMove> 中的 BaseMove 的类.

我遇到的问题。我在这里找到了答案... HERE ...

"Mark BaseMove class with XmlInclude attribute passing your derived class as parameter:"

[XmlInclude(typeof(Scratch))]
public class BaseMove
{
public BaseMove()
{
}
}

工作起来很有魅力!那我为什么要在这里发帖呢?新问题。我有 HUNDREDS 个源自 BaseMove 的 Action 。有快捷方式还是我必须在 XmlInclude 中编写每个“typeof(...)”?

编辑 - 我找到的另一个解决方案。

public static Type[] GetAllSubTypes(Type aBaseClass)
{
List<Type> result = new List<Type>();
Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly a in assemblies)
{
Type[] types = a.GetTypes();
foreach (Type t in types)
{
if (t.IsSubclassOf(aBaseClass))
result.Add(t);
}
}
return result.ToArray();
}

然后在序列化期间,我只是调用此函数以用作 extraTypes 的数组。

Type[] extraTypes = GetAllSubTypes(typeof(BaseMove));
XmlSerializer xml = new XmlSerializer(typeof(List<BaseEnemy>), extraTypes);

最佳答案

您可以遍历应用程序域中的所有程序集,从您的基类型中找到所有可分配的类型,并在构造您的 XmlSerializer 时将它们作为已知类型传递。但是,一些注意事项:

  1. 程序集是按需加载的,因此您不能只执行一次搜索,并且
  2. XmlSerializer 构建后,必须缓存在哈希表或字典中并重复使用以防止内存和资源泄漏。参见 here了解详情。

因此,你可以这样做:

public static class XmlSerializerWithKnownTypeCreator<T>
{
static Dictionary<HashSet<Type>, XmlSerializer> table = new Dictionary<HashSet<Type>, XmlSerializer>(HashSet<Type>.CreateSetComparer());

public static XmlSerializer CreateKnownTypeSerializer<TRoot>()
{
return CreateKnownTypeSerializer(new Type [] {typeof(TRoot)});
}

public static XmlSerializer CreateKnownTypeSerializer(IEnumerable<Type> baseTypes)
{
var set = new HashSet<Type>(
AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetTypes())
.Where(t => baseTypes.Any(baseType => baseType.IsAssignableFrom(t))));
lock (table)
{
XmlSerializer serializer;
if (table.TryGetValue(set, out serializer))
return serializer;

table[set] = serializer = new XmlSerializer(typeof(T), set.ToArray());
return serializer;
}
}
}

然后这样调用它:

var serializer = XmlSerializerWithKnownTypeCreator<DocumentRoot>.CreateKnownTypeSerializer<BaseMove>();

例如,

var serializer = XmlSerializerWithKnownTypeCreator<List<BaseClass>>.CreateKnownTypeSerializer<BaseMove>();

更新

如果序列化器的参数化通用静态表看起来很奇怪(公平地说,确实有点奇怪),您可以将序列化器存储在非通用全局哈希表中,如 documentation 中所建议的那样:

If you use any of the other constructors, multiple versions of the same assembly are generated and never unloaded, which results in a memory leak and poor performance. The easiest solution is to use one of the previously mentioned two constructors. Otherwise, you must cache the assemblies in a Hashtable, as shown in the following example.

但是,该文档掩盖了如何为 XmlSerializer 生成 key 。代码示例也不是线程安全的,也许是因为所有这些东西都可以追溯到 .Net 1.0。所以这里有一些逻辑可以在全局哈希表中正确地键入和回收具有已知额外类型的 XmlSerializer:

public abstract class XmlserializerKey
{
readonly Type serializerType;

public XmlserializerKey(Type serializerType)
{
this.serializerType = serializerType;
}

protected Type SerializerType { get { return serializerType; } }

public override bool Equals(object obj)
{
if (ReferenceEquals(this, obj))
return true;
else if (ReferenceEquals(null, obj))
return false;
if (GetType() != obj.GetType())
return false;
XmlserializerKey other = (XmlserializerKey)obj;
if (other.serializerType != serializerType)
return false;
return true;
}

public override int GetHashCode()
{
int code = 0;
if (serializerType != null)
code ^= serializerType.GetHashCode();
return code;
}

public override string ToString()
{
return string.Format("Serializer type: " + serializerType.ToString());
}
}

public abstract class XmlserializerKeyWithExtraTypes : XmlserializerKey
{
static IEqualityComparer<HashSet<Type>> comparer;

readonly HashSet<Type> moreTypes = new HashSet<Type>();

static XmlserializerKeyWithExtraTypes()
{
comparer = HashSet<Type>.CreateSetComparer();
}

public XmlserializerKeyWithExtraTypes(Type serializerType, IEnumerable<Type> extraTypes)
: base(serializerType)
{
if (extraTypes != null)
foreach (var type in extraTypes)
moreTypes.Add(type);
}

protected Type[] MoreTypes { get { return moreTypes.ToArray(); } }

public override bool Equals(object obj)
{
if (!base.Equals(obj))
return false;
XmlserializerKeyWithExtraTypes other = (XmlserializerKeyWithExtraTypes)obj;
return comparer.Equals(moreTypes, other.moreTypes);
}

public override int GetHashCode()
{
int code = base.GetHashCode();
if (moreTypes != null)
code ^= comparer.GetHashCode(moreTypes);
return code;
}
}

public sealed class XmlSerializerKeyWithKnownTypes : XmlserializerKeyWithExtraTypes
{
public XmlSerializerKeyWithKnownTypes(Type serializerType, IEnumerable<Type> otherTypes)
: base(serializerType, otherTypes)
{
}

public XmlSerializer CreateSerializer()
{
return new XmlSerializer(SerializerType, MoreTypes);
}
}

public static class XmlSerializerHashTable
{
static Dictionary<object, XmlSerializer> dict;

static XmlSerializerHashTable()
{
dict = new Dictionary<object, XmlSerializer>();
}

public static XmlSerializer DemandSerializer(object key, Func<object, XmlSerializer> factory)
{
lock (dict)
{
XmlSerializer value;
if (!dict.TryGetValue(key, out value))
dict[key] = value = factory(key);
return value;
}
}
}

public static class XmlSerializerWithKnownDerivedTypesCreator
{
public static XmlSerializer CreateKnownTypeSerializer(Type type, IEnumerable<Type> extraTypes)
{
var allExtraTypes =
AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetTypes())
.Where(t => extraTypes.Any(extraType => extraType.IsAssignableFrom(t)));
var key = new XmlSerializerKeyWithKnownTypes(type, allExtraTypes);
return XmlSerializerHashTable.DemandSerializer(key, k => ((XmlSerializerKeyWithKnownTypes)k).CreateSerializer());
}
}

然后以与调用等效的 XmlSerializer 相同的方式调用它构造函数:

    public static void Test2()
{
List<BaseClass> list = new List<BaseClass>();
list.Add(new BaseClass());
list.Add(new MidClass());
list.Add(new DerivedClass1());
list.Add(new DerivedClass2());

var serializer = XmlSerializerWithKnownDerivedTypesCreator.CreateKnownTypeSerializer(list.GetType(), new Type[] { typeof(BaseClass) });
string xml = XmlSerializationHelper.GetXml(list, serializer, false);
Debug.WriteLine(xml);

// No assert below:
Debug.Assert(object.ReferenceEquals(serializer, XmlSerializerWithKnownDerivedTypesCreator.CreateKnownTypeSerializer(list.GetType(), new Type[] { typeof(BaseClass) })));
}

关于c# - 无效操作异常 : The type of the argument object 'Scratch' is not primitive,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27391485/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com