Fix potential order inconsistency of element and property lists.

This commit is contained in:
2023-03-03 11:45:16 +08:00
parent 215f72b3b5
commit da60dc0903
12 changed files with 134 additions and 27 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c4ef48e4a4983de4e9c31483df2a918e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9ec674235c0dd6744af2dab2b58dd53c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
using System.Collections;
using System.Collections.Generic;
namespace Cryville.Common.Collections.Generic {
public interface IPairList : IList {
void Add(object key, object value);
}
public interface IPairList<TKey, TValue> : IList<KeyValuePair<TKey, TValue>>, IPairList {
void Add(TKey key, TValue value);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 73fb17b484b343242bcce27c15ed7d44
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections;
namespace Cryville.Common.Collections.Generic {
public struct PairCollection : IDisposable {
public void Dispose() { }
IPairList _pairList;
IDictionary _dictionary;
public PairCollection(object collection) : this() {
var type = collection.GetType();
if (typeof(IPairList).IsAssignableFrom(type)) _pairList = (IPairList)collection;
else if (typeof(IDictionary).IsAssignableFrom(type)) _dictionary = (IDictionary)collection;
else throw new ArgumentException("Parameter is not a pair collection");
}
public void Add(object key, object value) {
if (_pairList != null) _pairList.Add(key, value);
else _dictionary.Add(key, value);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2517e8f040bd36f46948e5fafaf5335c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
namespace Cryville.Common.Collections.Generic {
public class PairList : List<KeyValuePair<object, object>>, IPairList {
public void Add(object key, object value) {
Add(new KeyValuePair<object, object>(key, value));
}
}
public class PairList<TKey, TValue> : List<KeyValuePair<TKey, TValue>>, IPairList<TKey, TValue> {
public void Add(TKey key, TValue value) {
Add(new KeyValuePair<TKey, TValue>(key, value));
}
public void Add(object key, object value) {
try {
Add((TKey)key, (TValue)value);
}
catch (InvalidCastException) {
throw new ArgumentException("Wrong key type or value type");
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d9ed5ea8b7b1a934287e7ec5971166c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -5,7 +5,7 @@ namespace Cryville.Common.Pdt {
/// Indicates that the attributed member is an element list.
/// </summary>
/// <remarks>
/// <para>An element list is a <see cref="System.Collections.IDictionary" /> that represents a collection of PDT elements. There must be at most one element list in a class.</para>
/// <para>An element list is a <see cref="System.Collections.IDictionary" /> or <see cref="Cryville.Common.Collections.Generic.IPairList" /> that represents a collection of PDT elements. There must be at most one element list in a class.</para>
/// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ElementListAttribute : Attribute { }
@@ -14,7 +14,7 @@ namespace Cryville.Common.Pdt {
/// Indicates that the attributed member is a property list.
/// </summary>
/// <remarks>
/// <para>A property list is a <see cref="System.Collections.IDictionary" /> that represents a collection of PDT properties. There must be at most one property list in a class.</para>
/// <para>A property list is a <see cref="System.Collections.IDictionary" /> or <see cref="Cryville.Common.Collections.Generic.IPairList" /> that represents a collection of PDT properties. There must be at most one property list in a class.</para>
/// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class PropertyListAttribute : Attribute { }

View File

@@ -1,4 +1,5 @@
using System;
using Cryville.Common.Collections.Generic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
@@ -255,13 +256,13 @@ namespace Cryville.Common.Pdt {
if (prop == null) throw new MissingMemberException(string.Format("The property \"{0}\" is not found", pkey));
Type ptype = ReflectionHelper.GetMemberType(prop);
if (flag) {
if (!typeof(IDictionary).IsAssignableFrom(ptype))
throw new InvalidOperationException("Internal error: Element list is not a dictionary");
var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1];
object key = _binder.ChangeType(pkey, ktype, null);
object value = InterpretObject(vtype);
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value);
using (var collection = new PairCollection(ReflectionHelper.GetValue(prop, result))) {
var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1];
object key = _binder.ChangeType(pkey, ktype, null);
object value = InterpretObject(vtype);
collection.Add(key, value);
}
}
else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype));
}
@@ -284,13 +285,13 @@ namespace Cryville.Common.Pdt {
if (prop == null) throw new MissingMemberException(string.Format("The property \"{0}\" is not found", pkey));
var ptype = ReflectionHelper.GetMemberType(prop);
if (flag) {
if (!typeof(IDictionary).IsAssignableFrom(ptype))
throw new InvalidOperationException("Internal error: Property list is not a dictionary");
var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1];
object key = _binder.ChangeType(pkey, ktype, null);
object value = _binder.ChangeType(exp, vtype, null);
((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value);
using (var collection = new PairCollection(ReflectionHelper.GetValue(prop, result))) {
var ktype = ptype.GetGenericArguments()[0];
var vtype = ptype.GetGenericArguments()[1];
object key = _binder.ChangeType(pkey, ktype, null);
object value = _binder.ChangeType(exp, vtype, null);
collection.Add(key, value);
}
}
else {
object value = _binder.ChangeType(exp, ptype, null);