225 lines
6.8 KiB
C#
225 lines
6.8 KiB
C#
using System.Reflection;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace RobotNet10.ScriptEngine.Shared;
|
|
|
|
public static partial class ScriptHelpers
|
|
{
|
|
public static string ToString(ParameterInfo parameter)
|
|
{
|
|
var modifier = "";
|
|
if (parameter.IsDefined(typeof(ParamArrayAttribute), false))
|
|
modifier = "params ";
|
|
else if (parameter.IsIn && parameter.ParameterType.IsByRef && !parameter.IsOut)
|
|
modifier = "in ";
|
|
else if (parameter.IsOut)
|
|
modifier = "out ";
|
|
else if (parameter.ParameterType.IsByRef)
|
|
modifier = "ref ";
|
|
|
|
var typeString = ScriptHelpers.ToString(
|
|
parameter.ParameterType.IsByRef
|
|
? parameter.ParameterType.GetElementType()!
|
|
: parameter.ParameterType
|
|
);
|
|
|
|
var defaultValue = "";
|
|
if (parameter.HasDefaultValue)
|
|
{
|
|
if (parameter.DefaultValue != null)
|
|
{
|
|
if (parameter.ParameterType.IsEnum)
|
|
{
|
|
defaultValue = $" = {ScriptHelpers.ToString(parameter.ParameterType)}.{parameter.DefaultValue}";
|
|
}
|
|
else if (parameter.DefaultValue is string)
|
|
{
|
|
defaultValue = $" = \"{parameter.DefaultValue}\"";
|
|
}
|
|
else if (parameter.DefaultValue is bool b)
|
|
{
|
|
defaultValue = $" = {b.ToString().ToLower()}";
|
|
}
|
|
else
|
|
{
|
|
defaultValue = $" = {parameter.DefaultValue}";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
defaultValue = " = null";
|
|
}
|
|
}
|
|
|
|
return $"{modifier}{typeString} {parameter.Name}{defaultValue}";
|
|
}
|
|
|
|
public static string ToString(Type type)
|
|
{
|
|
if (type == typeof(void)) return "void";
|
|
|
|
if (type.IsGenericType)
|
|
{
|
|
var genericTypeName = type.GetGenericTypeDefinition().FullName;
|
|
if (genericTypeName == null)
|
|
return type.Name;
|
|
|
|
var backtickIndex = genericTypeName.IndexOf('`');
|
|
if (backtickIndex > 0)
|
|
genericTypeName = genericTypeName[..backtickIndex];
|
|
|
|
var genericArgs = type.GetGenericArguments();
|
|
var argsString = string.Join(", ", genericArgs.Select(ToString));
|
|
return $"{genericTypeName}<{argsString}>";
|
|
}
|
|
|
|
return type.FullName ?? type.Name;
|
|
}
|
|
|
|
|
|
public static Type? ResolveTypeFromString(string typeString)
|
|
{
|
|
typeString = typeString.Trim();
|
|
|
|
// Handle array types (e.g., System.Int32[], string[], List<int>[])
|
|
if (typeString.EndsWith("[]"))
|
|
{
|
|
var elementTypeString = typeString[..^2].Trim();
|
|
var elementType = ResolveTypeFromString(elementTypeString);
|
|
return elementType?.MakeArrayType();
|
|
}
|
|
|
|
// Trường hợp không phải generic
|
|
if (!typeString.Contains('<'))
|
|
{
|
|
return FindType(typeString);
|
|
}
|
|
|
|
// Tách phần generic
|
|
var match = GenericTypeRegex.Match(typeString);
|
|
if (!match.Success)
|
|
return null;
|
|
|
|
var genericTypeName = match.Groups["raw"].Value;
|
|
var genericArgsString = match.Groups["args"].Value;
|
|
|
|
// Phân tách các generic argument (xử lý nested generics)
|
|
var genericArgs = SplitGenericArguments(genericArgsString);
|
|
|
|
var genericType = FindType(genericTypeName + "`" + genericArgs.Count);
|
|
if (genericType == null)
|
|
return null;
|
|
|
|
var resolvedArgs = genericArgs.Select(ResolveTypeFromString).ToArray();
|
|
if (resolvedArgs.Any(t => t == null))
|
|
return null;
|
|
|
|
return genericType.MakeGenericType(resolvedArgs!);
|
|
}
|
|
|
|
public static bool ResolveValueFromString(string valueStr, Type type, out object? value)
|
|
{
|
|
// Check if type is in MissionParameterTypes
|
|
if (!SupportedTypes.Values.Contains(type))
|
|
{
|
|
value = null;
|
|
return false;
|
|
}
|
|
|
|
// Convert string to the corresponding type
|
|
if (type == typeof(string))
|
|
{
|
|
value = valueStr;
|
|
return true;
|
|
}
|
|
|
|
if (type.IsEnum)
|
|
{
|
|
value = Enum.Parse(type, valueStr, ignoreCase: true);
|
|
return true;
|
|
}
|
|
|
|
// Handle nullable types
|
|
var underlyingType = Nullable.GetUnderlyingType(type);
|
|
if (underlyingType != null)
|
|
{
|
|
value = null;
|
|
return false;
|
|
}
|
|
|
|
value = Convert.ChangeType(valueStr, type);
|
|
if (value is null)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private static List<string> SplitGenericArguments(string input)
|
|
{
|
|
var args = new List<string>();
|
|
var sb = new StringBuilder();
|
|
int depth = 0;
|
|
|
|
foreach (char c in input)
|
|
{
|
|
if (c == ',' && depth == 0)
|
|
{
|
|
args.Add(sb.ToString().Trim());
|
|
sb.Clear();
|
|
}
|
|
else
|
|
{
|
|
if (c == '<') depth++;
|
|
else if (c == '>') depth--;
|
|
sb.Append(c);
|
|
}
|
|
}
|
|
|
|
if (sb.Length > 0)
|
|
{
|
|
args.Add(sb.ToString().Trim());
|
|
}
|
|
|
|
return args;
|
|
}
|
|
|
|
public static Type? FindType(string typeName)
|
|
{
|
|
if (SupportedTypes.TryGetValue(typeName, out var systemType)) return systemType;
|
|
|
|
return AppDomain.CurrentDomain
|
|
.GetAssemblies()
|
|
.Select(a => a.GetType(typeName, false))
|
|
.FirstOrDefault(t => t != null);
|
|
}
|
|
|
|
public static readonly IReadOnlyDictionary<string, Type> SupportedTypes = new Dictionary<string, Type>()
|
|
{
|
|
["bool"] = typeof(bool),
|
|
["byte"] = typeof(byte),
|
|
["sbyte"] = typeof(sbyte),
|
|
["short"] = typeof(short),
|
|
["ushort"] = typeof(ushort),
|
|
["int"] = typeof(int),
|
|
["uint"] = typeof(uint),
|
|
["long"] = typeof(long),
|
|
["ulong"] = typeof(ulong),
|
|
["double"] = typeof(double),
|
|
["float"] = typeof(float),
|
|
["double"] = typeof(double),
|
|
["char"] = typeof(char),
|
|
["string"] = typeof(string),
|
|
["object"] = typeof(object),
|
|
};
|
|
|
|
private static readonly Regex GenericTypeRegex = CreateGenericTypeRegex();
|
|
|
|
[GeneratedRegex(@"^(?<raw>[^<]+)<(?<args>.+)>$")]
|
|
private static partial Regex CreateGenericTypeRegex();
|
|
}
|