Files
hjha-server/GameDAL/ExpressionsParser/ValueComparer.cs
xiaoou e9616125ce feat: initial commit - HJHA game server full source
6 major server modules (PdkFriendServer/GlobalSever/ServerCore/GameModule/GameNetModule) +
game logic (GameFix/GameDAL/ServerData) +
network layer (NetWorkMessage) +
data layer (ObjectModel) +
utilities (MrWu/Core/Config/CloudAPI/dll) +
adapters (zyxAdapter/base)

.NET 8.0 C# solution, 16 projects, 958 source files
2026-07-07 12:02:15 +08:00

145 lines
4.0 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Reflection;
namespace ExpressionsParser {
/// <summary>
/// Generic "by value" comparer that uses IComparable and can compare arrays/lists.
/// </summary>
public class ValueComparer : IComparer, IComparer<object>, IValueComparer {
internal readonly static ValueComparer _Instance = new ValueComparer();
public static IValueComparer Instance {
get {
return _Instance;
}
}
/// <summary>
/// Gets or sets format provider used for Convert.ChangeType (InvariantCulture by default).
/// </summary>
public IFormatProvider FormatProvider { get; set; }
/// <summary>
/// Determines how ValueComparer handles comparison exceptions (by default is false: convert exceptions are thrown).
/// </summary>
public bool SuppressErrors { get; set; }
/// <summary>
/// Determines how ValueComparer handles comparison with nulls (default is "MinValue" mode).
/// </summary>
public NullComparisonMode NullComparison { get; set; }
public ValueComparer() {
FormatProvider = System.Globalization.CultureInfo.InvariantCulture;
SuppressErrors = false;
}
private bool IsAssignableFrom(Type a, Type b) {
#if NET40
return a.IsAssignableFrom(b);
#else
return a.GetTypeInfo().IsAssignableFrom(b.GetTypeInfo() );
#endif
}
int IComparer.Compare(object a, object b) {
var res = CompareInternal(a, b);
if (!res.HasValue)
throw new ArgumentException(string.Format("Cannot compare {0} and {1}", a.GetType(), b.GetType()));
return res.Value;
}
int IComparer<object>.Compare(object a, object b) {
return ((IComparer)this).Compare(a, b);
}
public int? Compare(object a, object b) {
try {
if (NullComparison == NullComparisonMode.Sql)
if (a == null || b == null)
return null;
return CompareInternal(a, b);
} catch {
if (SuppressErrors)
return null;
throw;
}
}
protected virtual int? CompareInternal(object a, object b) {
if (a == null && b == null)
return 0;
if (a == null && b != null)
return -1;
if (a != null && b == null)
return 1;
if ((a is IList) && (b is IList)) {
IList aList = (IList)a;
IList bList = (IList)b;
if (aList.Count < bList.Count)
return -1;
if (aList.Count > bList.Count)
return +1;
for (int i = 0; i < aList.Count; i++) {
int? r = Compare(aList[i], bList[i]);
if (!r.HasValue || r != 0)
return r;
}
// lists are equal
return 0;
}
// test for quick compare if a type is assignable from b
if (a is IComparable) {
var aComp = (IComparable)a;
// quick compare if types are fully compatible
if (IsAssignableFrom( a.GetType(), b.GetType() ))
return aComp.CompareTo(b);
}
if (b is IComparable) {
var bComp = (IComparable)b;
// quick compare if types are fully compatible
if (IsAssignableFrom( b.GetType(), a.GetType() ))
return -bComp.CompareTo(a);
}
// try to convert b to a and then compare
if (a is IComparable) {
var aComp = (IComparable)a;
var bConverted = Convert.ChangeType(b, a.GetType(), FormatProvider);
return aComp.CompareTo(bConverted);
}
// try to convert a to b and then compare
if (b is IComparable) {
var bComp = (IComparable)b;
var aConverted = Convert.ChangeType(a, b.GetType(), FormatProvider);
return -bComp.CompareTo(aConverted);
}
return null;
}
public enum NullComparisonMode {
/// <summary>
/// Null compared as "MinValue" (affects less-than and greater-than comparisons).
/// </summary>
/// <remarks>This is default behaviour expected for <see cref="IComparer"/> and described in MSDN.</remarks>
MinValue = 0,
/// <summary>
/// Null cannot be compared to any other value (even if it is null). This is SQL-like nulls handling.
/// </summary>
Sql = 1,
}
}
}