//------------------------------------------------------------------------------------------------------------------------ public static bool Convert(object value, Type ToType, out object result) { result = null; //try convert try { //get value type var fromType = value == null ? typeof(object) : value.GetType(); //nothing to do? if (fromType == ToType) { result = value; return(true); } //are both single values? if ((!fromType.IsArray && !ToType.IsArray) || (value == null)) { if (SingleValueConvert(value, ToType, out result)) { return(true); } else if (value is string && value != null && (value as string).Contains(ArraySeparator)) { //we may be able to convert this string if we split it by the separator and pick the first element var elems = (value as string).Split(ArraySeparator); return(SingleValueConvert(elems[0], ToType, out result)); } else { return(false); } } //get parameters var src_arr = (value as Array); var src_length = src_arr == null ? 0 : src_arr.Length; var ToTypeElement = ToType.IsArray ? ToType.GetElementType() : ToType; //zero length array? if (fromType.IsArray && src_length == 0) { //create a zero-length result array result = Array.CreateInstance(ToTypeElement, 0); return(true); } //is source only an array? if (fromType.IsArray && !ToType.IsArray) { //if target is string then we can join them up into a nice string, else just pick the first value if (ToType == typeof(string)) { //build result string by joining up elements string res = ""; for (int n = 0; n < src_length; n++) { object v; if (SingleValueConvert(src_arr.GetValue(n), ToTypeElement, out v) == false) { return(false); } res += v.ToStringInvariant() + ArraySeparator; } result = res; return(true); } else { return(SingleValueConvert(src_arr.GetValue(0), ToType, out result)); } } //is only destination an array? else if (!fromType.IsArray && ToType.IsArray) { //if source is string try to split it into elements if (fromType == typeof(string)) { //split using separator var elems = (value as string).Split(ArraySeparator); //create result array var dst_arr = Array.CreateInstance(ToTypeElement, elems.Length); for (int n = 0; n < elems.Length; n++) { object v; if (SingleValueConvert(elems[n], ToTypeElement, out v) == false) { return(false); } dst_arr.SetValue(v, n); } result = dst_arr; return(true); } else { //create a zero-length result array var dst_arr = Array.CreateInstance(ToTypeElement, 1); object v; if (SingleValueConvert(value, ToTypeElement, out v) == false) { return(false); } dst_arr.SetValue(v, 0); result = dst_arr; return(true); } } //are both arrays? else if (fromType.IsArray && ToType.IsArray) { //create result array var dst_arr = Array.CreateInstance(ToTypeElement, src_length); //fill with a per-element convert for (int n = 0; n < src_length; n++) { object v; if (SingleValueConvert(src_arr.GetValue(n), ToTypeElement, out v) == false) { return(false); } dst_arr.SetValue(v, n); } result = dst_arr; return(true); } else { DebugEx.Assert("Should not be here (Convert from=" + fromType + ", to=" + ToType + ")"); return(false); } } catch { result = null; return(false); } //pokemon exception handler }
//------------------------------------------------------------------------------------------------------------------------ public static Type GetType(string name, bool DeFriendlify = true) { //sanity check if (string.IsNullOrWhiteSpace(name)) { return(null); } //find type Type result = null; lock (cache) if (cache.TryGetValue(name, out result) == false) { try { //resolve type result = Type.GetType(name); //If null go for fallback mechanisms if (result == null) { //This is now in fallback. do not keep lock since what follows are expensive operations Monitor.Exit(cache); try { //if not found and not fully qualified search in all assemblies if (result == null) { string strippedName; //process name (strip assembly and recersivly extract generic types) if (name.Contains('[')) { var lefovers = name.RightOf("["); var generics = new List <string>(); int i = 0; int start = 0; for (int n = 0; n < lefovers.Length; n++) { var c = lefovers[n]; if (c == '[') { if (i == 0) { start = n + 1; } i++; } else if (c == ']') { i--; if (i == 0) { generics.Add(lefovers.Substring(start, n - start)); start = n + 1; } } } //get types for each generic var genericsTypes = new List <Type>(); foreach (var entry in generics) { var gt = GetType(entry); if (gt == null) { return(null); } genericsTypes.Add(gt); } //process found generics recursively strippedName = name.LeftOf("`") + "`" + generics.Count + "[" + string.Join(", ", genericsTypes.Select(t => "[" + t.AssemblyQualifiedName + "]")) + "]"; //try a fast re-check of processed name result = Type.GetType(strippedName); } else { strippedName = name.LeftOf(","); } //search assemblies if (result == null) { foreach (var entry in GetAssemblies()) { result = entry.GetType(strippedName); if (result != null) { break; } } } } //Try to find friendly named types if (result == null && DeFriendlify) { try { result = Type.GetType(Extensions.DeFriendlifyName(name)); } catch (Exception ex) { DebugEx.Assert(ex, "DeFriendlifyName failed"); } } } catch (Exception ex) { DebugEx.Assert(ex, "Caught unhandled exception during type resolve"); } finally { Monitor.Enter(cache); } //re-aquire lock before continuing } } catch (Exception ex) { DebugEx.Assert(ex, "Unhandled excpetion while trying to resolve type"); } //cache it cache.ForceAdd(name, result); } //done and done return(result); }
//------------------------------------------------------------------------------------------------------------------------ public static bool SingleValueConvert(object value, Type toType, out object result) { result = null; //try convert try { //if nullable extract wrapped type #if NETFX var isNullable = toType.IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable <>); #elif UNIVERSAL var isNullable = toType.GetTypeInfo().IsGenericType&& toType.GetGenericTypeDefinition() == typeof(Nullable <>); #endif if (isNullable) { toType = toType.GenericTypeArguments[0]; } try { //get value type var fromType = value == null ? typeof(object) : value.GetType(); var ToTypeIsInteger = toType.IsInteger(); var ToTypeIsDecimal = toType.IsDecimal(); var ToTypeIsNumber = ToTypeIsInteger || ToTypeIsDecimal; //universal helpers #if NETFX var ToTypeInfo = toType; var FromTypeInfo = fromType; #elif UNIVERSAL var ToTypeInfo = toType.GetTypeInfo(); var FromTypeInfo = fromType.GetTypeInfo(); #endif //nothing to do? if (fromType == toType) { result = value; return(true); } //check for enums if (ToTypeInfo.IsEnum && fromType != typeof(string) && toType.GetEnumUnderlyingType() != fromType) { //try to convert to target type object convValue = null; if (Convert(value, toType.GetEnumUnderlyingType(), out convValue)) { value = convValue?.ToStringInvariant(); fromType = typeof(string); #if UNIVERSAL FromTypeInfo = fromType.GetTypeInfo(); #endif } } //check easy stuff if (value != null && ToTypeInfo.IsAssignableFrom(FromTypeInfo)) { result = value; return(true); } #if NETFX else if (value is string && typeof(IFillFromString).IsAssignableFrom(toType)) #elif UNIVERSAL else if (value is string && typeof(IFillFromString).GetTypeInfo().IsAssignableFrom(ToTypeInfo)) #endif { var box = Activator.CreateInstance(toType) as IFillFromString; box.FillFromString((string)value); result = box; return(true); } //special string cases if (value is string) { var str = value as string; if (str != null) { str = str.ToLowerInvariant().Trim(); } //string->boolean cases if (toType == typeof(Boolean)) { double fv; Int64 iv; if (str.TryParse(out fv)) { result = fv != 0; return(true); } else if (str.TryParse(out iv)) { result = iv != 0; return(true); } } //special cases for string if (!ToTypeInfo.IsEnum) { if (string.IsNullOrEmpty(str) && ToTypeInfo.IsPrimitive && toType != typeof(string)) { fromType = typeof(bool); value = false; } else if (str == "true" || str == "false") { fromType = typeof(bool); value = str == "true" ? true : false; } else if (str == "yes" || str == "no") { fromType = typeof(bool); value = str == "yes" ? true : false; } else if (str == "on" || str == "off") { fromType = typeof(bool); value = str == "on" ? true : false; } else if (str == "enabled" || str == "disabled") { fromType = typeof(bool); value = str == "enabled" ? true : false; } else if (str == "enable" || str == "disable") { fromType = typeof(bool); value = str == "enable" ? true : false; } else if (str == "active" || str == "inactive") { fromType = typeof(bool); value = str == "active" ? true : false; } else if (str == "activate" || str == "deactivate") { fromType = typeof(bool); value = str == "activate" ? true : false; } else if (str == "activated" || str == "deactivated") { fromType = typeof(bool); value = str == "activated" ? true : false; } } //nothing to do? if (fromType == toType) { result = value; return(true); } //number converter if (ToTypeIsNumber) { double dv; if (str.TryParse(out dv)) { value = dv; fromType = typeof(double); } } } //custom converters if (fromType == typeof(Boolean)) { if (toType == typeof(float)) { result = (bool)value ? 1f : 0f; return(true); } else if (toType == typeof(byte)) { result = (bool)value ? (byte)1 : (byte)0; return(true); } else if (toType == typeof(sbyte)) { result = (bool)value ? (sbyte)1 : (sbyte)0; return(true); } else if (toType == typeof(double)) { result = (bool)value ? 1d : 0d; return(true); } else if (toType == typeof(decimal)) { result = (bool)value ? (decimal)1 : (decimal)0; return(true); } else if (toType == typeof(Int16)) { result = (bool)value ? (Int16)1 : (Int16)0; return(true); } else if (toType == typeof(Int32)) { result = (bool)value ? (Int32)1 : (Int32)0; return(true); } else if (toType == typeof(Int64)) { result = (bool)value ? (Int64)1 : (Int64)0; return(true); } else if (toType == typeof(UInt16)) { result = (bool)value ? (UInt16)1 : (UInt16)0; return(true); } else if (toType == typeof(UInt32)) { result = (bool)value ? (UInt32)1 : (UInt32)0; return(true); } else if (toType == typeof(UInt64)) { result = (bool)value ? (UInt64)1 : (UInt64)0; return(true); } else if (toType == typeof(string)) { result = (bool)value ? "True" : "False"; return(true); } else { result = null; return(false); } } //if input is null then give null back if (value == null) { result = ToTypeInfo.IsClass ? null : Activator.CreateInstance(toType); return(true); } #if NETFX //try forward convert { var convValue = TypeDescriptor.GetConverter(fromType); if (convValue.CanConvertTo(toType)) { result = convValue.ConvertTo(null, System.Globalization.CultureInfo.InvariantCulture, value, toType); //special object->string case (use json if objects ToString is the default typename) if (fromType.IsClass && toType == typeof(string) && (result as string) == fromType.FullName) { #if NEWTONSOFT result = value.ToJSON(); #endif } return(true); } } //try the other way around { var convType = TypeDescriptor.GetConverter(toType); if (convType.CanConvertFrom(fromType)) { //try the other way around result = convType.ConvertFrom(null, System.Globalization.CultureInfo.InvariantCulture, value); return(true); } } #endif //last attempt try { result = System.Convert.ChangeType(value, toType); //special object->string case (use json if objects ToString is the default typename) if (FromTypeInfo.IsClass && toType == typeof(string) && (result as string) == fromType.FullName) { #if NEWTONSOFT result = value.ToJSON(); #endif } return(true); } catch { } //string<->object special case using json if (fromType == typeof(string) && ToTypeInfo.IsClass) { #if NEWTONSOFT try { result = (value as string).FromJSON(toType); if (result != null && result.GetType() == toType) { return(true); } else { result = null; } } catch { } #endif } //failed result = null; return(false); } finally { //re-wrap with nullable (not sure if this is needed, because from debugger it will not do it anyway and c# will handle it internally.. but what-the-heck) if (isNullable) { var nullableType = typeof(Nullable <>).MakeGenericType(toType); try { result = Activator.CreateInstance(nullableType, new object[] { result }); } catch { } } } } catch (Exception ex) { DebugEx.TraceLog(ex, "Convert Error"); result = null; return(false); } //pokemon exception handler }
public static void StartTest() { var evr = new YEventRouter(); const int iterations = 1000000; //TimeSpan total_derived = TimeSpan.Zero; //TimeSpan total_direct = TimeSpan.Zero; Stopwatch watch = new Stopwatch(); int g = 0; //add 2 event handlers DebugEx.TraceLog("Adding handler1a/b and handler2"); evr.AddEventHandler <Payload1>((s, i, e) => { g++; }, 5); //evr.AddEventHandler<Payload1>(Handler1b); evr.AddEventHandler <Payload2>((s, i, e) => { g++; }, 6); //evr.AddEventHandler<Payload2>((s, i, e) => // { // DebugEx.TraceLog("HANDLER2 " + e + " called"); // //create new handler for this Type route (altering the internal hashset) // evr.AddEventHandler<Payload2>((x, y, z) => DebugEx.TraceLog("HANDLER2 created from within handler")); // //create new handler for a new Type route // evr.AddEventHandler<Payload2_3>((x, y, z) => DebugEx.TraceLog("HANDLER2_3 created from within handler")); // }); //evr.AddEventHandler<Payload2_2>((s, i, e) => DebugEx.TraceLog("DERIVED HANDLER2_2 " + e + " called")); //scale cpu clock up for (int i = 0; i < iterations; i++) { evr.TriggerEvent <Payload2_2>(null, new Payload2_2() { b = "Payload2_2" }); } //trigger events DebugEx.TraceLog("Trigger events"); watch.Start(); for (int i = 0; i < iterations; i++) { evr.TriggerEvent <Payload2_2>(null, new Payload2_2() { b = "Payload2_2" }); } watch.Stop(); var total_derived = watch.ElapsedMilliseconds; DebugEx.TraceLog("Total time for " + g + " derived iterations = " + total_derived); g = 0; watch.Restart(); for (int i = 0; i < iterations; i++) { evr.TriggerEvent <Payload2>(null, new Payload2() { b = "Payload1" }); } watch.Stop(); var total_direct = watch.ElapsedMilliseconds; DebugEx.TraceLog("Total time for " + g + " direct iterations = " + total_direct); evr.TriggerEvent <Payload2>(null, new Payload2() { b = "Payload2" }); evr.TriggerEvent <Payload1>(null, new Payload1() { a = "Payload1", c = "newtest" }); Task.Delay(3000).Wait(); evr.TriggerEvent <Payload1>(null, new Payload1() { a = "Payload1", c = "newtest" }); evr.TriggerEvent <Payload2>(null, new Payload2() { b = "Payload2" }); //remove handler1b DebugEx.TraceLog("removing handler1b"); evr.RemoveEventHandler <Payload1>(Handler1b); //trigger same events DebugEx.TraceLog("Trigger events"); evr.TriggerEvent <Payload1>(null, new Payload1() { a = "Payload1", c = "newtest" }); evr.TriggerEvent <Payload2>(null, new Payload2() { b = "Payload2" }); Task.Delay(3000).Wait(); evr.TriggerEvent <Payload1>(null, new Payload1() { a = "Payload1", c = "newtest" }); Task.Delay(3000).Wait(); evr.TriggerEvent <Payload1>(null, new Payload1() { a = "Payload1", c = "newtest" }); evr.TriggerEvent <Payload2>(null, new Payload2() { b = "Payload2" }); DebugEx.TraceLog("END"); }
public static void Handler1b(object sender, YEventRouter.EvInfo info, object ev) { DebugEx.TraceLog("HANDLER1b " + ev + " called"); }
//-------------------------------------------------------------------------------------------------------------------------------------- private void _ExecuteHandler <T>(object sender, T ev) { //declares SortedSetTS <EvHandler> allRoutesForType = null; var evType = typeof(T); //null check if (ev == null) { return; } //create event info var evInfo = new EvInfo() { priv = null, IsDerivedMatch = false, }; //Execute var executedCallbacks = new HashSet <object>(); while (evType != null && evType != typeof(object)) { //get routes for type allRoutesForType = _ActiveRoutes.TryGetOrDefault(evType); if (allRoutesForType != null) { //Broadcast event foreach (var evhandle in allRoutesForType) { if (!evInfo.IsDerivedMatch || evhandle.ReceiveDerivedTypeEvents) { try { //check that we haven't already run this callback if (!executedCallbacks.Contains(evhandle.Cb)) { //use Dynamic callback if derived type; use known type otherwise if (evInfo.IsDerivedMatch) { ((dynamic)evhandle.Cb)(sender, evInfo, ev); } else { ((EventCb <T>)evhandle.Cb)(sender, evInfo, ev); } //add to hashset so that it's not executed again executedCallbacks.Add(evhandle.Cb); } } catch (Exception ex) { DebugEx.TraceErrorException(ex); } } } } //now moving up the inheritance tree (toward object) #if NETFX evType = evType.BaseType; #elif UNIVERSAL evType = evType.GetTypeInfo().BaseType; #endif evInfo.IsDerivedMatch = true; } }
//------------------------------------------------------------------------------------------------------------------------ #endregion #region Functions //------------------------------------------------------------------------------------------------------------------------ void HeartBeatEntryPoint() { try { //declares TimeSpan?timeout = null; //spin while (isRunning) { lock (locker) { //check pending requests.. if none the sleep the good sleep if (RequestQueue.Count == 0) { timeout = TimeSpan.MaxValue; //infinite } else { //get first pending request (has smallest wake timestamp) var req = RequestQueue.First(); //get remaining time var rem = req.WakeupTimestamp - DateTime.UtcNow; if (rem.TotalMilliseconds > 0.5d) { timeout = rem; } else { //consume event RequestQueue.Dequeue(); RequestLookup.Remove(req.RequestID); //callback if (req.AsyncCallback) { Task.Run(() => { try { //fire event if (req.Callback != null) { req.Callback(req.UserData); } else if (req.WeakCallback != null) { req.WeakCallback.Invoke(req.UserData); } else { DebugEx.Assert("FutureCallbackQueue reqId:" + req.RequestID + " has no callback to invoke"); } } catch (Exception ex) { DebugEx.Assert(ex, "Unhandled exception in callback caught by FutureCallbackQueue"); } }); } else { //exit lock to fire event Monitor.Exit(locker); try { //fire event if (req.Callback != null) { req.Callback(req.UserData); } else if (req.WeakCallback != null) { req.WeakCallback.Invoke(req.UserData); } else { DebugEx.Assert("FutureCallbackQueue reqId:" + req.RequestID + " has no callback to invoke"); } } catch (Exception ex) { DebugEx.Assert(ex, "Unhandled exception in callback caught by FutureCallbackQueue"); } finally { Monitor.Enter(locker); } } //no timeout..keep spinning timeout = null; } } //sleep/wait manager if (timeout.HasValue) { int _clampedTimeout = (int)timeout.Value.TotalMilliseconds.ClampCeil(MaxSleepMilisecondsD); Monitor.Wait(locker, _clampedTimeout); if (!isRunning) { break; } } } } } catch (Exception ex) { DebugEx.TraceError(ex, "FutureCallbackQueue heartbeat failed"); } }