From 4c02eaea75a3fbb8b1e536b4aed857957fe02e4e Mon Sep 17 00:00:00 2001 From: Marc Hernandez Date: Thu, 4 Jul 2019 12:51:51 -0700 Subject: [PATCH] Add property logging --- Log.cs | 33 +++++++- Scr.cs | 203 ++++++++++++++++++++++++++++++++++++++++++++++++ SharpLib.csproj | 1 + 3 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 Scr.cs diff --git a/Log.cs b/Log.cs index fbce754..873292b 100644 --- a/Log.cs +++ b/Log.cs @@ -3,6 +3,8 @@ using System.IO; using System.Diagnostics; using System.Collections; using System.Runtime.CompilerServices; +using System.Collections.Generic; +using System.Reflection; //using System.Threading.Tasks; namespace lib @@ -135,7 +137,7 @@ namespace lib static public void log( string msg, LogType type = LogType.Debug, string cat = "unk", object obj = null ) { - lock(s_log) + lock( s_log ) { var evt = new LogEvent( type, cat, msg, obj ); @@ -143,6 +145,35 @@ namespace lib } } + + static public void logProps( object obj, string header, LogType type = LogType.Debug, string cat = "unk" ) + { + var list = scr.GetAllProperties( obj.GetType() ); + + + lock( s_log ) + { + var evt = new LogEvent( type, cat, header, obj ); + + s_log.writeToAll( evt ); + + foreach( var pi in list ) + { + try + { + var v = pi.GetValue( obj ); + + log( $"{pi.Name} = {v}", type, cat ); + } + catch( Exception ex ) + { + log( $"Exception processing {pi.Name} {ex.Message}", type, cat ); + } + } + + } + } + //This might seem a little odd, but the intent is that usually you wont need to set notExpectedValue. static public void expected( T value, string falseString, string trueString = "", T notExpectedValue = default(T) ) { diff --git a/Scr.cs b/Scr.cs new file mode 100644 index 0000000..87a63d5 --- /dev/null +++ b/Scr.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + + + + + + + + +static public class scr +{ + + public class PredEnumerator + { + public static PredEnumerator Create( IEnumerator en, Predicate pred ) + { + return new PredEnumerator( en, pred ); + } + + public static PredEnumerator Create( IEnumerable en, Predicate pred ) + { + return new PredEnumerator( en.GetEnumerator(), pred ); + } + } + + public class PredEnumerator : PredEnumerator, IEnumerator + { + + public T Current => m_en.Current; + + object IEnumerator.Current => m_en.Current; + + public PredEnumerator( IEnumerator en, Predicate pred ) + { + m_en = en; + m_pred = pred; + } + + + public bool MoveNext() + { + var success = m_en.MoveNext(); + + if( !success ) return false; + + while( !m_pred( m_en.Current ) && (success = m_en.MoveNext()) ) + { + + } + + return success; + } + + public void Reset() + { + m_en.Reset(); + } + + #region IDisposable Support + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose( bool disposing ) + { + if( !disposedValue ) + { + if( disposing ) + { + // TODO: dispose managed state (managed objects). + } + + // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. + // TODO: set large fields to null. + + disposedValue = true; + } + } + + // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. + // ~MyEnumerator() + // { + // // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + // Dispose(false); + // } + + // This code added to correctly implement the disposable pattern. + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose( true ); + // TODO: uncomment the following line if the finalizer is overridden above. + // GC.SuppressFinalize(this); + } + #endregion + + IEnumerator m_en; + Predicate m_pred; + } + + + public class PredEnumerable : IEnumerable + { + public PredEnumerable( PredEnumerator en ) + { + m_en = en; + } + + public IEnumerator GetEnumerator() + { + return m_en; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return m_en; + } + + PredEnumerator m_en; + } + + + public static void GetAllFields( Type t, List list ) + { + var fieldArr = t.GetFields( + BindingFlags.DeclaredOnly | + BindingFlags.NonPublic | + BindingFlags.Public | + BindingFlags.Instance); + + var en = PredEnumerator.Create( fieldArr.AsEnumerable(), fa => fa.GetCustomAttribute( typeof( NonSerializedAttribute ) ) == null ); + + list.AddRange( new PredEnumerable( en ) ); + + if( t.BaseType != null && t.BaseType != typeof( object ) ) + { + GetAllFields( t.BaseType, list ); + } + } + + + public static ImmutableList GetAllFields( Type t ) + { + if( s_fieldCache.TryGetValue( t, out var info ) ) + return info; + + var list = new List(); + + GetAllFields( t, list ); + + var immList = list.ToImmutableList(); + + s_fieldCache = s_fieldCache.Add( t, immList ); + + return immList; + } + + + public static void GetAllProperties( Type t, List list ) + { + var propArr = t.GetProperties( + BindingFlags.DeclaredOnly | + BindingFlags.NonPublic | + BindingFlags.Public | + BindingFlags.Instance); + + var en = PredEnumerator.Create( propArr.AsEnumerable(), fa => fa.GetCustomAttribute( typeof( NonSerializedAttribute ) ) == null ); + + list.AddRange( new PredEnumerable( en ) ); + + if( t.BaseType != null && t.BaseType != typeof( object ) ) + { + GetAllProperties( t.BaseType, list ); + } + } + + public static ImmutableList GetAllProperties( Type t ) + { + if( s_propCache.TryGetValue( t, out var info ) ) return info; + + var list = new List(); + + GetAllProperties( t, list ); + + var immList = list.ToImmutableList(); + + s_propCache = s_propCache.Add( t, immList ); + + return immList; + } + + + static ImmutableDictionary> s_fieldCache = ImmutableDictionary>.Empty; + static ImmutableDictionary> s_propCache = ImmutableDictionary>.Empty; + + + +} diff --git a/SharpLib.csproj b/SharpLib.csproj index 0de9e0c..1c23e98 100644 --- a/SharpLib.csproj +++ b/SharpLib.csproj @@ -126,6 +126,7 @@ +