fix: Makes guid settable. Cleans up type conversions (#765)
* Marks GUID a parsable type * Cleans up type conversions
This commit is contained in:
parent
1916dc00cb
commit
04b5a6c609
6 changed files with 155 additions and 416 deletions
|
|
@ -13,8 +13,6 @@ namespace Server.Commands
|
|||
{
|
||||
public static class Add
|
||||
{
|
||||
private static readonly object[] m_ParseArgs = new object[1];
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("Tile", AccessLevel.GameMaster, Tile_OnCommand);
|
||||
|
|
@ -245,7 +243,7 @@ namespace Server.Commands
|
|||
for (int i = 0, a = 0; i < paramList.Length; i++)
|
||||
{
|
||||
var param = paramList[i];
|
||||
var value = ParseValue(param.ParameterType, a < args.Length ? args[a++] : null);
|
||||
TryParse(param.ParameterType, a < args.Length ? args[a++] : null, out var value);
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
|
|
@ -264,56 +262,6 @@ namespace Server.Commands
|
|||
return values;
|
||||
}
|
||||
|
||||
public static object ParseValue(Type type, string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsEnum(type))
|
||||
{
|
||||
return Enum.Parse(type, value, true);
|
||||
}
|
||||
|
||||
if (IsType(type))
|
||||
{
|
||||
return AssemblyHandler.FindTypeByName(value);
|
||||
}
|
||||
|
||||
if (IsParsable(type))
|
||||
{
|
||||
return ParseParsable(type, value);
|
||||
}
|
||||
|
||||
object obj = value;
|
||||
|
||||
if (value.StartsWithOrdinal("0x"))
|
||||
{
|
||||
if (IsSignedNumeric(type))
|
||||
{
|
||||
obj = Convert.ToInt64(value[2..], 16);
|
||||
}
|
||||
else if (IsUnsignedNumeric(type))
|
||||
{
|
||||
obj = Convert.ToUInt64(value[2..], 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = Convert.ToInt32(value[2..], 16);
|
||||
}
|
||||
}
|
||||
|
||||
if (obj == null && !type.IsValueType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Convert.ChangeType(obj, type);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEntity Build(
|
||||
Mobile from, ConstructorInfo ctor, object[] values, string[,] props,
|
||||
PropertyInfo[] realProps, ref bool sendError
|
||||
|
|
@ -735,21 +683,6 @@ namespace Server.Commands
|
|||
InternalAvg_OnCommand(e, true);
|
||||
}
|
||||
|
||||
public static bool IsEnum(Type type) => type.IsSubclassOf(OfEnum);
|
||||
|
||||
public static bool IsType(Type type) => type == OfType || type.IsSubclassOf(OfType);
|
||||
|
||||
public static bool IsParsable(Type type) => type.IsDefined(OfParsable, false);
|
||||
|
||||
public static object ParseParsable(Type type, string value)
|
||||
{
|
||||
var method = type.GetMethod("Parse", ParseTypes);
|
||||
|
||||
m_ParseArgs[0] = value;
|
||||
|
||||
return method?.Invoke(null, m_ParseArgs);
|
||||
}
|
||||
|
||||
private enum TileZType
|
||||
{
|
||||
Start,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using Server.Buffers;
|
||||
using Server.Commands;
|
||||
using Server.Commands.Generic;
|
||||
using Server.Gumps;
|
||||
|
|
@ -21,7 +22,6 @@ namespace Server.Commands
|
|||
|
||||
public static class Properties
|
||||
{
|
||||
private static readonly object[] m_ParseParams = new object[1];
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
|
|
@ -204,8 +204,6 @@ namespace Server.Commands
|
|||
|
||||
public static string IncreaseValue(Mobile from, object o, string[] args)
|
||||
{
|
||||
// Type type = o.GetType();
|
||||
|
||||
var realObjs = new object[args.Length / 2];
|
||||
var realProps = new PropertyInfo[args.Length / 2];
|
||||
var realValues = new int[args.Length / 2];
|
||||
|
|
@ -287,12 +285,7 @@ namespace Server.Commands
|
|||
|
||||
if (realProps.Length == 1)
|
||||
{
|
||||
if (positive)
|
||||
{
|
||||
return "The property has been increased.";
|
||||
}
|
||||
|
||||
return "The property has been decreased.";
|
||||
return positive ? "The property has been increased." : "The property has been decreased.";
|
||||
}
|
||||
|
||||
if (positive && negative)
|
||||
|
|
@ -300,12 +293,7 @@ namespace Server.Commands
|
|||
return "The properties have been changed.";
|
||||
}
|
||||
|
||||
if (positive)
|
||||
{
|
||||
return "The properties have been increased.";
|
||||
}
|
||||
|
||||
return "The properties have been decreased.";
|
||||
return positive ? "The properties have been increased." : "The properties have been decreased.";
|
||||
}
|
||||
|
||||
private static string InternalGetValue(object o, PropertyInfo p, PropertyInfo[] chain = null)
|
||||
|
|
@ -345,17 +333,20 @@ namespace Server.Commands
|
|||
return $"{p.Name} = {toString}";
|
||||
}
|
||||
|
||||
var concat = new string[chain.Length * 2 + 1];
|
||||
|
||||
for (var i = 0; i < chain.Length; ++i)
|
||||
using var builder = new ValueStringBuilder();
|
||||
for (var i = 0; i < chain.Length; i++)
|
||||
{
|
||||
concat[i * 2 + 0] = chain[i].Name;
|
||||
concat[i * 2 + 1] = i < chain.Length - 1 ? "." : " = ";
|
||||
builder.Append(chain[i].Name);
|
||||
if (i < chain.Length - 1)
|
||||
{
|
||||
builder.Append(".");
|
||||
}
|
||||
}
|
||||
|
||||
concat[^1] = toString;
|
||||
builder.Append(" = ");
|
||||
builder.Append(toString);
|
||||
|
||||
return string.Concat(concat);
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public static string SetValue(Mobile from, object o, string name, string value)
|
||||
|
|
@ -368,104 +359,6 @@ namespace Server.Commands
|
|||
return p == null ? failReason : InternalSetValue(from, logObject, o, p, name, value, true);
|
||||
}
|
||||
|
||||
private static object Parse(object o, Type t, string value)
|
||||
{
|
||||
var method = t.GetMethod("Parse", ParseTypes);
|
||||
|
||||
m_ParseParams[0] = value;
|
||||
|
||||
return method?.Invoke(o, m_ParseParams);
|
||||
}
|
||||
|
||||
public static string ConstructFromString(Type type, object obj, string value, ref object constructed)
|
||||
{
|
||||
object toSet;
|
||||
var isSerial = IsSerial(type);
|
||||
|
||||
if (isSerial) // mutate into int32
|
||||
{
|
||||
type = OfInt;
|
||||
}
|
||||
|
||||
if (value == "(-null-)" && !type.IsValueType)
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
|
||||
if (IsEnum(type))
|
||||
{
|
||||
try
|
||||
{
|
||||
toSet = Enum.Parse(type, value ?? "", true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "That is not a valid enumeration member.";
|
||||
}
|
||||
}
|
||||
else if (IsType(type))
|
||||
{
|
||||
try
|
||||
{
|
||||
toSet = AssemblyHandler.FindTypeByName(value);
|
||||
|
||||
if (toSet == null)
|
||||
{
|
||||
return "No type with that name was found.";
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "No type with that name was found.";
|
||||
}
|
||||
}
|
||||
else if (IsParsable(type))
|
||||
{
|
||||
try
|
||||
{
|
||||
toSet = Parse(obj, type, value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "That is not properly formatted.";
|
||||
}
|
||||
}
|
||||
else if (value == null)
|
||||
{
|
||||
toSet = null;
|
||||
}
|
||||
else if (value.StartsWithOrdinal("0x") && IsNumeric(type))
|
||||
{
|
||||
try
|
||||
{
|
||||
toSet = Convert.ChangeType(Convert.ToUInt64(value[2..], 16), type);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "That is not properly formatted.";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
toSet = Convert.ChangeType(value, type);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "That is not properly formatted.";
|
||||
}
|
||||
}
|
||||
|
||||
if (isSerial) // mutate back
|
||||
{
|
||||
toSet = (Serial)(toSet ?? Serial.MinusOne);
|
||||
}
|
||||
|
||||
constructed = toSet;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string SetDirect(
|
||||
Mobile from, object logObject, object obj, PropertyInfo prop, string givenName,
|
||||
object toSet, bool shouldLog
|
||||
|
|
@ -475,16 +368,12 @@ namespace Server.Commands
|
|||
{
|
||||
if (toSet is AccessLevel newLevel)
|
||||
{
|
||||
var reqLevel = AccessLevel.Administrator;
|
||||
|
||||
if (newLevel == AccessLevel.Administrator)
|
||||
var reqLevel = newLevel switch
|
||||
{
|
||||
reqLevel = AccessLevel.Developer;
|
||||
}
|
||||
else if (newLevel >= AccessLevel.Developer)
|
||||
{
|
||||
reqLevel = AccessLevel.Owner;
|
||||
}
|
||||
AccessLevel.Administrator => AccessLevel.Developer,
|
||||
>= AccessLevel.Developer => AccessLevel.Owner,
|
||||
_ => AccessLevel.Administrator
|
||||
};
|
||||
|
||||
if (from.AccessLevel < reqLevel)
|
||||
{
|
||||
|
|
@ -511,42 +400,12 @@ namespace Server.Commands
|
|||
}
|
||||
}
|
||||
|
||||
public static string SetDirect(object obj, PropertyInfo prop, object toSet)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (toSet is AccessLevel)
|
||||
{
|
||||
return "You do not have access to that level.";
|
||||
}
|
||||
|
||||
prop.SetValue(obj, toSet, null);
|
||||
return "Property has been set.";
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "An exception was caught, the property may not be set.";
|
||||
}
|
||||
}
|
||||
|
||||
public static string InternalSetValue(
|
||||
Mobile from, object logobj, object o, PropertyInfo p, string pname,
|
||||
string value, bool shouldLog
|
||||
)
|
||||
{
|
||||
object toSet = null;
|
||||
var result = ConstructFromString(p.PropertyType, o, value, ref toSet);
|
||||
|
||||
return result ?? SetDirect(from, logobj, o, p, pname, toSet, shouldLog);
|
||||
}
|
||||
|
||||
public static string InternalSetValue(object o, PropertyInfo p, string value)
|
||||
{
|
||||
object toSet = null;
|
||||
var result = ConstructFromString(p.PropertyType, o, value, ref toSet);
|
||||
|
||||
return result ?? SetDirect(o, p, toSet);
|
||||
}
|
||||
) =>
|
||||
TryParse(p.PropertyType, value, out var toSet) ??
|
||||
SetDirect(from, logobj, o, p, pname, toSet, shouldLog);
|
||||
|
||||
|
||||
private class PropsTarget : Target
|
||||
|
|
|
|||
|
|
@ -679,12 +679,10 @@ namespace Server.Engines.Spawners
|
|||
{
|
||||
if (realProps[i] != null)
|
||||
{
|
||||
object toSet = null;
|
||||
var result = Properties.ConstructFromString(
|
||||
var result = Types.TryParse(
|
||||
realProps[i].PropertyType,
|
||||
entity,
|
||||
props[i, 1],
|
||||
ref toSet
|
||||
out var toSet
|
||||
);
|
||||
|
||||
if (result == null)
|
||||
|
|
|
|||
|
|
@ -361,12 +361,6 @@ namespace Server.Gumps
|
|||
)
|
||||
);
|
||||
}
|
||||
else if (IsType(type, OfString) || IsType(type, DecimalTypes) ||
|
||||
IsType(type, NumericTypes) ||
|
||||
IsType(type, OfText))
|
||||
{
|
||||
from.SendGump(new SetGump(prop, from, m_Object, this));
|
||||
}
|
||||
else if (IsType(type, OfPoison))
|
||||
{
|
||||
from.SendGump(
|
||||
|
|
@ -408,6 +402,10 @@ namespace Server.Gumps
|
|||
: new PropertiesGump(from, m_Object, m_Stack, m_List, m_Page)
|
||||
);
|
||||
}
|
||||
else if (IsParsable(type))
|
||||
{
|
||||
from.SendGump(new SetGump(prop, from, m_Object, this));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -471,40 +469,6 @@ namespace Server.Gumps
|
|||
private static bool HasAttribute(Type type, Type check, bool inherit) =>
|
||||
type.GetCustomAttributes(check, inherit).Length > 0;
|
||||
|
||||
private static bool HasImplicitCastTo(Type type, Type check)
|
||||
{
|
||||
foreach (var method in type.GetMethods(BindingFlags.Public | BindingFlags.Static))
|
||||
{
|
||||
if (method.Name != "op_Implicit" || !IsType(method.ReturnType, check))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var parameters = method.GetParameters();
|
||||
if (parameters.Length == 1 && IsType(parameters[0].ParameterType, type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsType(Type type, Type check) => type == check || type.IsSubclassOf(check);
|
||||
|
||||
private static bool IsType(Type type, Type[] check)
|
||||
{
|
||||
for (var i = 0; i < check.Length; ++i)
|
||||
{
|
||||
if (IsType(type, check[i]) || HasImplicitCastTo(type, check[i]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string ValueToString(PropertyInfo prop) => ValueToString(m_Object, prop);
|
||||
|
||||
public static string ValueToString(object obj, PropertyInfo prop)
|
||||
|
|
@ -559,7 +523,7 @@ namespace Server.Gumps
|
|||
return $"(?) 0x{serial.Value:X}";
|
||||
}
|
||||
|
||||
if (o is byte || o is sbyte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong)
|
||||
if (o is byte or sbyte or short or ushort or int or uint or long or ulong)
|
||||
{
|
||||
return $"{o} (0x{o:X})";
|
||||
}
|
||||
|
|
@ -679,107 +643,6 @@ namespace Server.Gumps
|
|||
return list;
|
||||
}
|
||||
|
||||
public static object GetObjectFromString(Type t, string s)
|
||||
{
|
||||
if (t == typeof(string))
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
if (t == typeof(byte) || t == typeof(sbyte) || t == typeof(short) || t == typeof(ushort) || t == typeof(int) ||
|
||||
t == typeof(uint) || t == typeof(long) || t == typeof(ulong))
|
||||
{
|
||||
if (s.StartsWithOrdinal("0x"))
|
||||
{
|
||||
if (t == typeof(ulong) || t == typeof(uint) || t == typeof(ushort) || t == typeof(byte))
|
||||
{
|
||||
return Convert.ChangeType(Convert.ToUInt64(s[2..], 16), t);
|
||||
}
|
||||
|
||||
return Convert.ChangeType(Convert.ToInt64(s[2..], 16), t);
|
||||
}
|
||||
|
||||
return Convert.ChangeType(s, t);
|
||||
}
|
||||
|
||||
if (t == typeof(double) || t == typeof(float))
|
||||
{
|
||||
return Convert.ChangeType(s, t);
|
||||
}
|
||||
|
||||
if (t.IsDefined(typeof(ParsableAttribute), false))
|
||||
{
|
||||
var parseMethod = t.GetMethod("Parse", new[] { typeof(string) });
|
||||
|
||||
return parseMethod?.Invoke(null, new object[] { s });
|
||||
}
|
||||
|
||||
throw new Exception("bad");
|
||||
}
|
||||
|
||||
private static string GetStringFromObject(object o)
|
||||
{
|
||||
if (o == null)
|
||||
{
|
||||
return "-null-";
|
||||
}
|
||||
|
||||
if (o is string s)
|
||||
{
|
||||
return $"\"{s}\"";
|
||||
}
|
||||
|
||||
if (o is bool)
|
||||
{
|
||||
return o.ToString();
|
||||
}
|
||||
|
||||
if (o is char c)
|
||||
{
|
||||
return $"0x{(int)c:X} '{c}'";
|
||||
}
|
||||
|
||||
if (o is Serial serial)
|
||||
{
|
||||
if (serial.IsValid)
|
||||
{
|
||||
if (serial.IsItem)
|
||||
{
|
||||
return $"(I) 0x{serial.Value:X}";
|
||||
}
|
||||
|
||||
if (serial.IsMobile)
|
||||
{
|
||||
return $"(M) 0x{serial.Value:X}";
|
||||
}
|
||||
}
|
||||
|
||||
return $"(?) 0x{serial.Value:X}";
|
||||
}
|
||||
|
||||
if (o is byte || o is sbyte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong)
|
||||
{
|
||||
return $"{o} (0x{o:X})";
|
||||
}
|
||||
|
||||
if (o is Mobile mobile)
|
||||
{
|
||||
return $"(M) 0x{mobile.Serial.Value:X} \"{mobile.Name}\"";
|
||||
}
|
||||
|
||||
if (o is Item item)
|
||||
{
|
||||
return $"(I) 0x{item.Serial.Value:X}";
|
||||
}
|
||||
|
||||
if (o is Type type)
|
||||
{
|
||||
return type.Name;
|
||||
}
|
||||
|
||||
return o.ToString();
|
||||
}
|
||||
|
||||
private class PropertySorter : IComparer<PropertyInfo>
|
||||
{
|
||||
public static readonly PropertySorter Instance = new();
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ namespace Server.Gumps
|
|||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
object toSet;
|
||||
object toSet = null;
|
||||
bool shouldSet, shouldSend = true;
|
||||
|
||||
switch (info.ButtonID)
|
||||
|
|
@ -133,7 +133,7 @@ namespace Server.Gumps
|
|||
{
|
||||
try
|
||||
{
|
||||
toSet = PropertiesGump.GetObjectFromString(m_Property.PropertyType, text.Text);
|
||||
Types.TryParse(m_Property.PropertyType, text.Text, out toSet);
|
||||
shouldSet = true;
|
||||
}
|
||||
catch
|
||||
|
|
@ -153,26 +153,20 @@ namespace Server.Gumps
|
|||
}
|
||||
case 2: // Null
|
||||
{
|
||||
toSet = null;
|
||||
shouldSet = true;
|
||||
|
||||
break;
|
||||
}
|
||||
case 3: // Hue Picker
|
||||
{
|
||||
toSet = null;
|
||||
shouldSet = false;
|
||||
shouldSend = false;
|
||||
|
||||
m_Mobile.SendHuePicker(new InternalPicker(m_Property, m_Mobile, m_Object, m_PropertiesGump));
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
toSet = null;
|
||||
shouldSet = false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,13 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class Types
|
||||
{
|
||||
private static readonly Type[] _parseStringParamTypes = { typeof(string) };
|
||||
private static readonly object[] _parseParams = new object[1];
|
||||
|
||||
public static readonly Type OfByte = typeof(byte);
|
||||
public static readonly Type OfSByte = typeof(sbyte);
|
||||
public static readonly Type OfShort = typeof(short);
|
||||
|
|
@ -12,6 +16,9 @@ namespace Server
|
|||
public static readonly Type OfUInt = typeof(uint);
|
||||
public static readonly Type OfLong = typeof(long);
|
||||
public static readonly Type OfULong = typeof(ulong);
|
||||
public static readonly Type OfFloat = typeof(float);
|
||||
public static readonly Type OfDouble = typeof(double);
|
||||
public static readonly Type OfDecimal = typeof(decimal);
|
||||
public static readonly Type OfObject = typeof(object);
|
||||
public static readonly Type OfBool = typeof(bool);
|
||||
public static readonly Type OfChar = typeof(char);
|
||||
|
|
@ -37,6 +44,7 @@ namespace Server
|
|||
public static readonly Type OfNoSort = typeof(NoSortAttribute);
|
||||
public static readonly Type OfEntity = typeof(IEntity);
|
||||
public static readonly Type OfConstructible = typeof(ConstructibleAttribute);
|
||||
public static readonly Type OfGuid = typeof(Guid);
|
||||
|
||||
public static readonly string[] BoolNames = { "True", "False" };
|
||||
public static readonly object[] BoolValues = { true, false };
|
||||
|
|
@ -47,8 +55,9 @@ namespace Server
|
|||
|
||||
public static readonly Type[] DecimalTypes =
|
||||
{
|
||||
typeof(float),
|
||||
typeof(double)
|
||||
OfFloat,
|
||||
OfDouble,
|
||||
OfDecimal
|
||||
};
|
||||
|
||||
public static readonly Type[] NumericTypes =
|
||||
|
|
@ -63,44 +72,127 @@ namespace Server
|
|||
OfULong
|
||||
};
|
||||
|
||||
private static readonly Type[] SignedNumerics =
|
||||
{
|
||||
OfLong,
|
||||
OfInt,
|
||||
OfShort,
|
||||
OfSByte
|
||||
};
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsType(Type type, Type check) => check.IsAssignableFrom(type);
|
||||
|
||||
private static readonly Type[] UnsignedNumerics =
|
||||
{
|
||||
OfULong,
|
||||
OfUInt,
|
||||
OfUShort,
|
||||
OfByte
|
||||
};
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsChar(Type t) => IsType(t, OfChar);
|
||||
|
||||
public static readonly Type[] ParseTypes = { OfString };
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsString(Type t) => IsType(t, OfString);
|
||||
|
||||
public static bool IsSerial(Type t) => t == OfSerial;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsText(Type t) => IsType(t, OfText);
|
||||
|
||||
public static bool IsType(Type t) => t == OfType;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsParsable(Type t) =>
|
||||
IsChar(t) || IsString(t) || IsType(t, OfGuid) ||
|
||||
IsType(t, OfTimeSpan) || IsNumeric(t) || IsDecimal(t) || t.IsDefined(OfParsable, false);
|
||||
|
||||
public static bool IsChar(Type t) => t == OfChar;
|
||||
|
||||
public static bool IsString(Type t) => t == OfString;
|
||||
|
||||
public static bool IsText(Type t) => t == OfText;
|
||||
|
||||
public static bool IsEnum(Type t) => t.IsEnum;
|
||||
|
||||
public static bool IsParsable(Type t) => t == OfTimeSpan || t.IsDefined(OfParsable, false);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsDecimal(Type t) => Array.IndexOf(DecimalTypes, t) >= 0;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsNumeric(Type t) => Array.IndexOf(NumericTypes, t) >= 0;
|
||||
|
||||
public static bool IsSignedNumeric(Type t) => Array.IndexOf(SignedNumerics, t) >= 0;
|
||||
|
||||
public static bool IsUnsignedNumeric(Type t) => Array.IndexOf(UnsignedNumerics, t) >= 0;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsEntity(Type t) => OfEntity.IsAssignableFrom(t);
|
||||
|
||||
public static object Parse(Type t, string value)
|
||||
{
|
||||
var method = t.GetMethod("Parse", _parseStringParamTypes);
|
||||
_parseParams[0] = value;
|
||||
return method?.Invoke(null, _parseParams);
|
||||
}
|
||||
|
||||
// Do not use this in "Parse" methods, it may cause a stack overflow
|
||||
public static string TryParse(Type type, string value, out object constructed)
|
||||
{
|
||||
constructed = null;
|
||||
var isSerial = IsType(type, OfSerial);
|
||||
|
||||
if (isSerial) // mutate into int32
|
||||
{
|
||||
type = OfInt;
|
||||
}
|
||||
|
||||
if (value == "(-null-)" && !type.IsValueType)
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
|
||||
if (IsType(type, OfEnum))
|
||||
{
|
||||
try
|
||||
{
|
||||
constructed = Enum.Parse(type, value ?? "", true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "That is not a valid enumeration member.";
|
||||
}
|
||||
}
|
||||
else if (IsType(type, OfType))
|
||||
{
|
||||
try
|
||||
{
|
||||
constructed = AssemblyHandler.FindTypeByName(value);
|
||||
|
||||
if (constructed == null)
|
||||
{
|
||||
return "No type with that name was found.";
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "No type with that name was found.";
|
||||
}
|
||||
}
|
||||
else if (value == null)
|
||||
{
|
||||
constructed = null;
|
||||
}
|
||||
else if (value.StartsWithOrdinal("0x") && IsNumeric(type))
|
||||
{
|
||||
try
|
||||
{
|
||||
constructed = Convert.ChangeType(Convert.ToUInt64(value[2..], 16), type);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "That is not properly formatted.";
|
||||
}
|
||||
}
|
||||
else if (IsParsable(type))
|
||||
{
|
||||
try
|
||||
{
|
||||
constructed = Parse(type, value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "That is not properly formatted.";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
constructed = Convert.ChangeType(value, type);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "That is not properly formatted.";
|
||||
}
|
||||
}
|
||||
|
||||
if (isSerial) // mutate back
|
||||
{
|
||||
constructed = (Serial)(constructed ?? Serial.MinusOne);
|
||||
}
|
||||
|
||||
constructed = constructed;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue