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
155 lines
4.6 KiB
C#
155 lines
4.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections;
|
|
using System.Text;
|
|
using System.Reflection;
|
|
|
|
namespace ExpressionsParser {
|
|
|
|
/// <summary>
|
|
/// Invoke object's method that is most compatible with provided arguments
|
|
/// </summary>
|
|
internal class InvokeMethod {
|
|
|
|
public object TargetObject { get; set; }
|
|
|
|
public string MethodName { get; set; }
|
|
|
|
public InvokeMethod(object o, string methodName) {
|
|
TargetObject = o;
|
|
MethodName = methodName;
|
|
}
|
|
|
|
protected MethodInfo FindMethod(Type[] argTypes) {
|
|
if (TargetObject is Type) {
|
|
// static method
|
|
#if NET40
|
|
return ((Type)TargetObject).GetMethod(MethodName, BindingFlags.Static | BindingFlags.Public);
|
|
#else
|
|
return ((Type)TargetObject).GetRuntimeMethod(MethodName, argTypes);
|
|
#endif
|
|
}
|
|
#if NET40
|
|
return TargetObject.GetType().GetMethod(MethodName, argTypes);
|
|
#else
|
|
return TargetObject.GetType().GetRuntimeMethod(MethodName, argTypes);
|
|
#endif
|
|
}
|
|
|
|
protected IEnumerable<MethodInfo> GetAllMethods() {
|
|
if (TargetObject is Type) {
|
|
#if NET40
|
|
return ((Type)TargetObject).GetMethods(BindingFlags.Static | BindingFlags.Public);
|
|
#else
|
|
return ((Type)TargetObject).GetRuntimeMethods();
|
|
#endif
|
|
}
|
|
#if NET40
|
|
return TargetObject.GetType().GetMethods();
|
|
#else
|
|
return TargetObject.GetType().GetRuntimeMethods();
|
|
#endif
|
|
}
|
|
|
|
public object Invoke(object[] args) {
|
|
Type[] argTypes = new Type[args.Length];
|
|
for (int i = 0; i < argTypes.Length; i++)
|
|
argTypes[i] = args[i] != null ? args[i].GetType() : typeof(object);
|
|
|
|
// strict matching first
|
|
MethodInfo targetMethodInfo = FindMethod(argTypes);
|
|
// fuzzy matching
|
|
if (targetMethodInfo==null) {
|
|
var methods = GetAllMethods();
|
|
|
|
foreach (var m in methods)
|
|
if (m.Name==MethodName &&
|
|
m.GetParameters().Length == args.Length &&
|
|
CheckParamsCompatibility(m.GetParameters(), argTypes, args)) {
|
|
targetMethodInfo = m;
|
|
break;
|
|
}
|
|
}
|
|
if (targetMethodInfo == null) {
|
|
string[] argTypeNames = new string[argTypes.Length];
|
|
for (int i=0; i<argTypeNames.Length; i++)
|
|
argTypeNames[i] = argTypes[i].Name;
|
|
string argTypeNamesStr = String.Join(",",argTypeNames);
|
|
throw new MissingMemberException(
|
|
(TargetObject is Type ? (Type)TargetObject : TargetObject.GetType()).FullName+"."+MethodName );
|
|
}
|
|
object[] argValues = PrepareActualValues(targetMethodInfo.GetParameters(),args);
|
|
object res = null;
|
|
try {
|
|
res = targetMethodInfo.Invoke( TargetObject is Type ? null : TargetObject, argValues);
|
|
} catch (TargetInvocationException tiEx) {
|
|
if (tiEx.InnerException!=null)
|
|
throw new Exception(tiEx.InnerException.Message, tiEx.InnerException);
|
|
else {
|
|
throw;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
internal static bool IsInstanceOfType(Type t, object val) {
|
|
#if NET40
|
|
return t.IsInstanceOfType(val);
|
|
#else
|
|
return val!=null && t.GetTypeInfo().IsAssignableFrom(val.GetType().GetTypeInfo());
|
|
#endif
|
|
}
|
|
|
|
protected bool CheckParamsCompatibility(ParameterInfo[] paramsInfo, Type[] types, object[] values) {
|
|
for (int i=0; i<paramsInfo.Length; i++) {
|
|
Type paramType = paramsInfo[i].ParameterType;
|
|
var val = values[i];
|
|
if (IsInstanceOfType(paramType, val))
|
|
continue;
|
|
// null and reference types
|
|
if (val==null &&
|
|
#if NET40
|
|
!paramType.IsValueType
|
|
#else
|
|
!paramType.GetTypeInfo().IsValueType
|
|
#endif
|
|
)
|
|
continue;
|
|
// possible autocast between generic/non-generic common types
|
|
try {
|
|
Convert.ChangeType(val, paramType, System.Globalization.CultureInfo.InvariantCulture);
|
|
continue;
|
|
} catch { }
|
|
//if (ConvertManager.CanChangeType(types[i],paramType))
|
|
// continue;
|
|
// incompatible parameter
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
protected object[] PrepareActualValues(ParameterInfo[] paramsInfo, object[] values) {
|
|
object[] res = new object[paramsInfo.Length];
|
|
for (int i=0; i<paramsInfo.Length; i++) {
|
|
if (values[i]==null || IsInstanceOfType( paramsInfo[i].ParameterType, values[i])) {
|
|
res[i] = values[i];
|
|
continue;
|
|
}
|
|
try {
|
|
res[i] = Convert.ChangeType( values[i], paramsInfo[i].ParameterType, System.Globalization.CultureInfo.InvariantCulture );
|
|
continue;
|
|
} catch {
|
|
throw new InvalidCastException(
|
|
String.Format("Invoke method '{0}': cannot convert argument #{1} from {2} to {3}",
|
|
MethodName, i, values[i].GetType(), paramsInfo[i].ParameterType));
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|