} // DisplayProperties method /// <summary> /// Enumerate the dependent assemblies. /// </summary> public void EnumerateDependents( ) { string strDispCount = NumberFormatters.Integer(_lstNamesOfDependentAssemblies.Count); int intMaxWidth = strDispCount.Length; string strDtlFmt = string.Concat(" {0,", intMaxWidth, "}: {1}"); Console.WriteLine( Properties.Resources.MSG_ASM_DEPENDENTS_LIST_HEADER, // Format Control String _asmRoot.FullName, // Format Item 0 = Assembly Full Name strDispCount, // Format Item 1 = Dependent Count Environment.NewLine); // Format Item 2 = Embedded Newline for (int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT; intJ < _lstNamesOfDependentAssemblies.Count; intJ++) { Console.WriteLine( strDtlFmt, // Format Control String NumberFormatters.Integer( // Format Item 0 = Item number ArrayInfo.OrdinalFromIndex( // int pintAnyInteger intJ)), // int pintIndex _lstNamesOfDependentAssemblies [intJ].FullName); // Format Item 1 = Assembly Full Name } // for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < _lstNamesOfDependentAssemblies.Count ; intJ++ ) Console.WriteLine( Properties.Resources.MSG_ASM_DEPENDENTS_LIST_TAIL, // Format Control String _asmRoot.FullName, // Format Item 0 = Assembly Full Name Environment.NewLine); // Format Item 1 = Embedded Newline } // EnumerateDependents
}; // static readonly FileInfoExtensionMethods.FileDetailsToShow [ ] s_aenmDetailsToShow internal static int Exercise ( ref int pintTestNumber ) { const string TEST_REPORT_PREAMBLE = @"{2}Testing ShowFileDetails extension method with FileDetailsToShow = {0} ({1}):"; const string TEST_REPORT_TEMPLATE_ABS = @" Case {0}: Information gathered based on absolute file name: "; const string TEST_REPORT_TEMPLATE_REL = @" Case {0}: Information gathered based on relative file name: "; NewClassTests_20140914.BeginTest ( System.Reflection.MethodBase.GetCurrentMethod ( ).Name , ref pintTestNumber , Program.BEGIN_TEST_TAKE_METHOD_NAME_AT_FACE_VALUE ); string strRootAssemblyDirectory = Program.s_smTheApp.AppRootAssemblyFileDirName; string strRelativeFileName = @"..\..\..\Test_Data\MD5_File_Digests.DOCX"; string strAbsoluteFileName = Path.Combine ( strRootAssemblyDirectory , strRelativeFileName ); Console.WriteLine ( @"strRootAssemblyDirectory = {0}" , strRootAssemblyDirectory ); Console.WriteLine ( @"strRelativeFileName = {0}" , strRelativeFileName ); Console.WriteLine ( @"strAbsoluteFileName = {0}" , strAbsoluteFileName ); // ---------------------------------------------------------------- // Since everything uses the same two FileInfo objects, they may as // well be hoisted above the For loop. // ---------------------------------------------------------------- FileInfo infoAbsolute1 = new FileInfo ( strAbsoluteFileName ); FileInfo infoAbsolute2 = new FileInfo ( infoAbsolute1.FullName ); for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < s_aenmDetailsToShow.Length ; intJ++ ) { Console.WriteLine ( TEST_REPORT_PREAMBLE , // Format Control String with 4 tokens ( int ) s_aenmDetailsToShow [ intJ ] , // Format Item 0: FileDetailsToShow = {0} ( s_aenmDetailsToShow [ intJ ] , // Format Item 1: ({1}): intJ == ArrayInfo.ARRAY_FIRST_ELEMENT // Format Item 2: {2}Testing ShowFileDetails ? Environment.NewLine // First iteration : SpecialStrings.EMPTY_STRING ); // Subsequent iterations Console.WriteLine ( infoAbsolute1.ShowFileDetails ( s_aenmDetailsToShow [ intJ ] , // FileDetailsToShow penmFileDetailsToShow = FileDetailsToShow.Everything string.Format ( // string pstrLabel = null TEST_REPORT_TEMPLATE_REL , // Format Control String with 1 token ArrayInfo.OrdinalFromIndex ( intJ ) ) , // Format Item 0: Case {0}: Information true , // bool pfPrefixWithNewline = false true ) ); // bool pfSuffixWithNewline = false Console.WriteLine ( infoAbsolute1.ShowFileDetails ( s_aenmDetailsToShow [ intJ ] , // FileDetailsToShow penmFileDetailsToShow = FileDetailsToShow.Everything string.Format ( // string pstrLabel = null TEST_REPORT_TEMPLATE_ABS , // Format Control String with 1 token ArrayInfo.OrdinalFromIndex ( intJ ) ) , // Format Item 0: Case {0}: Information false , // bool pfPrefixWithNewline = false true ) ); // bool pfSuffixWithNewline = false } // for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < s_aenmDetailsToShow.Length ; intJ++ ) return NewClassTests_20140914.TestDone ( MagicNumbers.ERROR_SUCCESS , pintTestNumber ); } // internal static int Exercise
} // BeginTest method /// <summary> /// Create a report of the contents of the deserialized response in /// <paramref name="timeSeriesDailyResponse"/>. /// </summary> /// <param name="timeSeriesDailyResponse"> /// The populated TimeSeriesDailyResponse instance returned by the JSON /// deserializer. /// </param> internal static void ConsumeResponse ( string pstrReportFileName , TimeSeriesDailyResponse timeSeriesDailyResponse ) { Console.WriteLine ( Properties.Resources.MSG_RESPONSE_METADATA , // Format control string new object [ ] { timeSeriesDailyResponse.Meta_Data.Information , // Format item 0: Information = {0} timeSeriesDailyResponse.Meta_Data.Symbol , // Format Item 1: Symbol = {1} timeSeriesDailyResponse.Meta_Data.LastRefreshed , // Format Item 2: LastRefreshed = {2} timeSeriesDailyResponse.Meta_Data.OutputSize , // Format Item 3: OutputSize = {3} timeSeriesDailyResponse.Meta_Data.TimeZone , // Format Item 4: TimeZone = {4} timeSeriesDailyResponse.Time_Series_Daily.Length , // Format Item 5: Detail Count = {5} Environment.NewLine // Format Item 6: Platform-dependent newline } ); string strAbsoluteInputFileName = AssembleAbsoluteFileName ( pstrReportFileName ); using ( StreamWriter swTimeSeriesDetail = new StreamWriter ( strAbsoluteInputFileName , FileIOFlags.FILE_OUT_CREATE , System.Text.Encoding.ASCII , MagicNumbers.CAPACITY_08KB ) ) { string strLabelRow = Properties.Resources.MSG_RESPONSE_DETAILS_LABELS.ReplaceEscapedTabsInStringFromResX ( ); swTimeSeriesDetail.WriteLine ( strLabelRow ); string strDetailRowFormatString = ReportHelpers.DetailTemplateFromLabels ( strLabelRow ); for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < timeSeriesDailyResponse.Time_Series_Daily.Length ; intJ++ ) { Time_Series_Daily daily = timeSeriesDailyResponse.Time_Series_Daily [ intJ ]; swTimeSeriesDetail.WriteLine ( strDetailRowFormatString , new object [ ] { ArrayInfo.OrdinalFromIndex ( intJ ) , // Format Item 0: Item Beautify ( daily.Activity_Date) , // Format Item 1: Activity_Date Beautify ( daily.Open ) , // Format Item 2: Open Beautify ( daily.High ) , // Format Item 3: High Beautify ( daily.Low ) , // Format Item 4: Low Beautify ( daily.Close ) , // Format Item 5: Close Beautify ( daily.AdjustedClose ) , // Format Item 6: AdjustedClose Beautify ( daily.Volume ) , // Format Item 7: Volume Beautify ( daily.DividendAmount ) , // Format Item 8: DividendAmount Beautify ( daily.SplitCoefficient ) // Format Item 9: SplitCoefficient } ); } // for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < timeSeriesDailyResponse.Time_Series_Daily.Length ; intJ++ ) } // using ( StreamWriter swTimeSeriesDetail = new StreamWriter ( strAbsoluteInputFileName , FileIOFlags.FILE_OUT_CREATE , System.Text.Encoding.ASCII , MagicNumbers.CAPACITY_08KB ) ) Console.WriteLine ( ShowFileDetails ( // Print the returned string. Properties.Resources.FILE_LABEL_CONTENT_REPORT , // string pstrLabel strAbsoluteInputFileName , // string pstrFileName true , // bool pfPrefixWithNewline = false false ) ); // bool pfSuffixWithNewline = true } // private static void ConsumeResponse
} // TestFormatItemCounters private static void ListAllErrors ( List<FormatStringError> plstAllErrors ) { const int ORDINAL_FROM_SUBSCRIPT = ArrayInfo.INDEX_FROM_ORDINAL; const int POS_LABEL = ArrayInfo.ARRAY_FIRST_ELEMENT; const int POS_VALUE = ArrayInfo.ARRAY_SECOND_ELEMENT; const char DELIMITER = FormatStringError.LABEL_VALUE_DELIMITER; ReportDetail.DetailFormat = "{3} {0} = {1}"; int intErrorCount = plstAllErrors.Count; for ( int intI = ArrayInfo.ARRAY_FIRST_ELEMENT ; intI < intErrorCount ; intI++ ) { FormatStringError fse = plstAllErrors [ intI ]; string [ ] astrErrorDetails = fse.Split ( ); int intNDetails = astrErrorDetails.Length; // Save a trip into the collection. ReportDetails rptDtlsColl = new ReportDetails ( intNDetails ); string [ ] astrErrorSummaryFirst = new string [ ] { string.Format ( Properties.Resources.MSG_FORMAT_ERROR_DETAILS , // Format template string FormatItem.XofY ( // Format Item 0 intI + ORDINAL_FROM_SUBSCRIPT , // X = Item Number intErrorCount ) ) // Y = Item Count }; // string [ ] astrErrorSummaryFirst // ------------------------------------------------------------ // Maybe there is a better way to accompish this. Nevertheless, // this method works for generating a completely blank string // of a length that must be determined at runtime. // ------------------------------------------------------------ string [ ] astrErrorSummaryAllOthers = new string [ ] { string.Empty.PadRight ( astrErrorSummaryFirst [ ArrayInfo.ARRAY_FIRST_ELEMENT ].Length ) }; // string [ ] astrErrorSummaryAllOthers for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < intNDetails ; intJ++ ) { string [ ] astrLabelAndValue = astrErrorDetails [ intJ ].Split ( DELIMITER ); rptDtlsColl.Add ( new ReportDetail ( astrLabelAndValue [ POS_LABEL ].Trim ( ) , // Label (Format Item = 0) astrLabelAndValue [ POS_VALUE ].Trim ( ) , // Value (Format Item = 1) as String ( ReportDetail.ItemDisplayOrder ) ArrayInfo.OrdinalFromIndex ( intJ ) , // Item Number (Format Item = 2) - The arithmetic operation casts it to int (signed), so it must be forcibly cast back to unsigned int. null , // Individual Format String (Null = Use Default from static property) ( intJ == ArrayInfo.ARRAY_FIRST_ELEMENT ) // Additional Details - Condition ? astrErrorSummaryFirst // Value if Condition is True : astrErrorSummaryAllOthers ) ); // Value if Condition is False } // for ( uint uintJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; uintJ < intNDetails ; uintJ++ ) rptDtlsColl.ListAllItems ( ); } // for ( int intI = ArrayInfo.ARRAY_FIRST_ELEMENT ; intI < intErrorCount ; intI++ ) } // ListAllErrors
} // InitializeInstance /// <summary> /// Enumeate missing configuration values, if any. /// </summary> /// <returns> /// This method returns a message suitable for display on a console or a /// Windows message box. The returned message summarises the state of /// affairs, even when all defined values are represented in the /// configuration file. /// </returns> public string EnumerateMissingConfigurationValues ( ) { MissingConfigSettings = MissingConfigSettings ?? UnconfiguredDLLSettings.TheOnlyInstance; List<UnconfiguredDLLSettings.UnconfiguredSetting> missing = MissingConfigSettings.GetMissingPropsForFile ( System.IO.Path.GetFileName ( _strAssemblyLocation ) ); if ( missing.Count > ListInfo.LIST_IS_EMPTY ) { System.Text.StringBuilder sbMessages = new System.Text.StringBuilder ( MagicNumbers.CAPACITY_04KB ); // ------------------------------------------------------------ // Start with a heading. // ------------------------------------------------------------ sbMessages.AppendFormat ( Properties.Resources.MSG_SOME_CONFIG_SETTINGS_OMITTED , MissingConfigSettings.Count , _DllConfigSettings.Count , AssemblyLocation , Environment.NewLine ); // ------------------------------------------------------------ // List each item in turn. // ------------------------------------------------------------ for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < MissingConfigSettings.Count ; intJ++ ) { sbMessages.AppendFormat ( Properties.Resources.MSG_ACCEPTED_DEFAULT_VALUE , // Format Control String: {0} of {1}: {2} = {3}{4} ArrayInfo.OrdinalFromIndex ( intJ ) , // Format Item 0: {0} of MissingConfigSettings.Count , // Format Item 1: of {1} missing [ intJ ].PropName , // Format Item 2: : {2} missing [ intJ ].PropValue , // Format Item 3: = {3} Environment.NewLine ); // Format Item 4: newline } // for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < MissingConfigSettings.Count ; intJ++ ) // ------------------------------------------------------------ // End with a footing. // ------------------------------------------------------------ sbMessages.AppendFormat ( Properties.Resources.MSG_ACCEPTED_LIST_END , Environment.NewLine ); return sbMessages.ToString ( ); } // TRUE (One or more settings is missing from the configuration file.) block, if ( base.MissingConfigSettings.Count > ListInfo.LIST_IS_EMPTY ) else { return string.Format ( Properties.Resources.MSG_ALL_CONFIG_SETTINGS_COVERED , _DllConfigSettings.Count , AssemblyLocation ); } // FALSE (All configuration settings are covered by the configuration file.) block, if ( base.MissingConfigSettings.Count > ListInfo.LIST_IS_EMPTY ) } // public string EnumerateMissingConfigurationValues
} // public FileInfo GetFirstFileInfo /// <summary> /// Unless the list is empty, return the oldest file in it, which is the /// last file in the list, since it is reverse sorted by LastWriteTime. /// </summary> /// <returns> /// The returned FileInfo object represents the oldest file in the list, /// which occupies its last slot, since the list is sorted in reverse /// order by LastWriteTimeUTC. /// </returns> public FileInfo GetLastFileInfo( ) { if (_lstMatchingFiles.Count > ListInfo.LIST_IS_EMPTY) { // Unless the list is empty, there must be a "first" item to return. return(_lstMatchingFiles [ArrayInfo.OrdinalFromIndex(_lstMatchingFiles.Count)].Details); } // TRUE (anticipated outcome) block, if ( _lstMatchingFiles.Count > ListInfo.LIST_IS_EMPTY ) else { // Since FileInfo is a nullable type, the degenerate case returns a null reference. return(null); } // FALSE (unanticipated outcome) block, if ( _lstMatchingFiles.Count > ListInfo.LIST_IS_EMPTY ) } // public FileInfo GetLastFileInfo
} // public static void ListKeyAssemblyProperties /// <summary> /// List selected properties of any assembly on a console. /// </summary> /// <param name="pasmSubject"> /// Pass in a reference to the desired assembly, which may be the /// assembly that exports a specified type, the executing assembly, the /// calling assembly, the entry assembly, or any other assembly for /// which you can obtain a reference. /// </param> /// <param name="pintJ"> /// Pass in the array subscript, a 32 bit signed integer. /// </param> /// <param name="pintNDependents"> /// Pass in the array element count, a 32 bit signed integer. /// </param> public static void ShowKeyAssemblyProperties( Assembly pasmSubject, int pintJ, int pintNDependents) { AssemblyName MyNameIs = AssemblyName.GetAssemblyName(pasmSubject.Location); System.Diagnostics.FileVersionInfo myVersionInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(pasmSubject.Location); int intItemOrdinal = ArrayInfo.OrdinalFromIndex(pintJ); Console.WriteLine( Properties.Resources.MSG_ASM_PROPS_SELECTED_DLL_PROPS_BEGIN, // Format Control String intItemOrdinal, // Format Item 0: Selected properties of assembly {0} pintNDependents, // Format Item 1: of {1} pasmSubject.FullName, // Format Item 2: , {2} Environment.NewLine); // Format Item 3: {3} Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_ASSEMBLYFILEBASENAME, Path.GetFileNameWithoutExtension(pasmSubject.Location)); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_VERSIONSTRING, myVersionInfo.FileVersion); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_ASSEMBLYVERSION, MyNameIs.Version); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_CULTURE, MyNameIs.CultureInfo.DisplayName); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_PUBLICKEYTOKEN, ByteArrayFormatters.ByteArrayToHexDigitString(MyNameIs.GetPublicKeyToken( ))); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_RUNTIME_VERSION, pasmSubject.ImageRuntimeVersion); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_ASSEMBLYGUIDSTRING, GetAssemblyGuidString(pasmSubject)); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_PRODUCTNAME, myVersionInfo.ProductName); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_LEGALCOPYRIGHT, myVersionInfo.LegalCopyright); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_LEGALTRADEMARKS, myVersionInfo.LegalTrademarks); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_COMPANYNAME, myVersionInfo.CompanyName); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_DESCRIPTION, myVersionInfo.FileDescription); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_COMMENTS, myVersionInfo.Comments, Environment.NewLine); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_ASSEMBYDIRNAME, Path.GetDirectoryName(pasmSubject.Location)); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_ASSEMBLYFILENAME, Path.GetFileName(pasmSubject.Location), Environment.NewLine); FileInfo fiLibraryFile = new FileInfo(pasmSubject.Location); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_FILE_CREATION_DATE, fiLibraryFile.CreationTime, fiLibraryFile.CreationTimeUtc); Console.WriteLine(Properties.Resources.MSG_ASM_PROPS_FILE_MODIFIED_DATE, fiLibraryFile.LastWriteTime, fiLibraryFile.LastWriteTimeUtc); Console.WriteLine( Properties.Resources.MSG_ASM_PROPS_SELECTED_DLL_PROPS_END, // Format Control String intItemOrdinal, // Format Item 0: End of selected properties of assembly {0} pintNDependents, // Format Item 1: of {1} Environment.NewLine); // Format Item 2: Bookend the string with platform-dependent newlines. } // public static void ShowKeAssemblyProperties method
/// <summary> /// Unless sumething is wrong with it, return the input <paramref name="pafixupPairs"/> /// to the calling routine. /// </summary> /// <param name="pafixupPairs"> /// Array of StringFixup structures to validate /// </param> /// <returns> /// If the method succeeds, the return value is a reference to the input <paramref name="pafixupPairs"/>. /// Otherwise, the method throws an ArgumentNullException exception or /// an ArgumentException exception, depending on the circumstances. /// </returns> /// <exception cref="ArgumentNullException"> /// An ArgumentNullException exception arises when the entire <paramref name="pafixupPairs"/> /// array is a null reference. /// </exception> /// <exception cref="ArgumentException"> /// An ArgumentException exception arises when the entire array is empty /// or one of its InputValue members is a null reference or the empty /// string. /// </exception> internal static StringFixup [ ] ValidateFixupPairArray ( StringFixup [ ] pafixupPairs ) { if ( pafixupPairs == null ) { throw new ArgumentNullException ( nameof ( pafixupPairs ) ); } // TRUE (unanticipated outcome) block, if ( pafixupPairs == null ) else { if ( pafixupPairs.Length == ArrayInfo.ARRAY_IS_EMPTY ) { throw new ArgumentException ( Core.Properties.Resources.ERRMSG_ARRAY_IS_EMPTY , nameof ( pafixupPairs ) ); } // TRUE (unanticipated outcome) block, if ( pafixupPairs.Length == ArrayInfo.ARRAY_IS_EMPTY ) else { for ( int intK = ArrayInfo.ARRAY_FIRST_ELEMENT ; intK < pafixupPairs.Length ; intK++ ) { if ( string.IsNullOrEmpty ( pafixupPairs [ intK ].InputValue ) ) { throw new ArgumentException ( string.Format ( Core.Properties.Resources.ERRMSG_STRING_FIXUP_PAIR_IS_INVALID , new object [ ] { ArrayInfo.OrdinalFromIndex ( intK ), // Format Item 0: at ordinal position {0} ( intK , // Format Item 1: (subscript = {1}) pafixupPairs [ intK ].OutputValue , // Format Item 2: The OutputValue at that position is {2}, pafixupPairs [ intK ].OutputValue == null // Format Item 3: which is {3}. ? Common.Properties.Resources.MSG_VALUE_IS_INVALID : Common.Properties.Resources.MSG_VALUE_IS_VALID , Environment.NewLine // Format Item 4: is a null reference or the empty string.{4} } ) , nameof ( pafixupPairs ) ); } // if ( string.IsNullOrEmpty ( pafixupPairs [ intK ].InputValue ) ) } // for ( int intK = ArrayInfo.ARRAY_FIRST_ELEMENT ; intK < pafixupPairs.Length ; intK++ ) return pafixupPairs; } // FALSE (anticipated outcome) block, if ( pafixupPairs.Length == ArrayInfo.ARRAY_IS_EMPTY ) } // FALSE (anticipated outcome) block, if ( pafixupPairs == null ) } // internal static StringFixup [ ] ValidateFixupPairArray
} // static void Main private static void ReportScenarioOutcome ( string pstrScenarioLabel , string [ ] pastrTestOutput , int pintNFields ) { Console.WriteLine ( pstrScenarioLabel , Environment.NewLine ); for ( int intCurrField = ArrayInfo.ARRAY_FIRST_ELEMENT ; intCurrField < pintNFields ; intCurrField++ ) { Console.WriteLine ( Properties.Resources.MSG_CASE_DETAIL , ArrayInfo.OrdinalFromIndex ( intCurrField ) , pintNFields , pastrTestOutput [ intCurrField ] ); } // for ( int intCurrField = StandardConstants.ARRAY_FIRST_ELEMENT ; intCurrField < intNFields ; intCurrField++ ) } //private static void ReportScenarioOutcome
} // private int FixNextItem /// <summary> /// After it finds and replaces its string, FixNextItem calls upon this /// routine to look just past it for string FIRST_ITEM_BREAK_POST, and /// replace it with SUBSEQUENT_ITEM_BREAK_POST. /// </summary> /// <param name="pstrInput"> /// This routine receives the string copy made by FixNextItem, so that /// it can reinitialize the StringBuilder before it starts appending /// text from it. /// </param> /// <param name="pintMatchPosition"> /// The character position where FixNextItem found its match becomes the /// starting point for the search performed by this routine. /// </param> /// <param name="pintMatchLength"> /// The length of the string matched by FixNextItem is fed into this /// routine, which adds it to <paramref name="pintMatchPosition"/> to /// determine where to begin its own search. /// </param> /// <param name="psbOut"> /// Although it is initialized and repopulated, passing around a /// StringBuilder is simpler than using an out parameter. /// </param> /// <returns></returns> private int FixThisItem ( string pstrInput , int pintMatchPosition , int pintMatchLength , StringBuilder psbOut ) { const string FIRST_ITEM_BREAK_POST = "\n {\n \"Activity_Date\": \""; // Post: },\n {\n {\n "Activity_Date": " const string SUBSEQUENT_ITEM_BREAK_POST = ",\n {\n \"Activity_Date\": \""; // Post: },\n {\n {\n "Activity_Date": " const int DATE_TOKEN_LENGTH = 11; const int DATE_TOKEN_SKIP_CHARS = DATE_TOKEN_LENGTH + 3; int intSkipOverMatchedCharacters = pintMatchPosition + pintMatchLength; psbOut.Clear ( ); psbOut.Append ( pstrInput.Substring ( ListInfo.SUBSTR_BEGINNING , ArrayInfo.OrdinalFromIndex ( pintMatchPosition ) ) ); psbOut.Append ( _fIsFirstPass ? FIRST_ITEM_BREAK_POST : SUBSEQUENT_ITEM_BREAK_POST ); psbOut.Append ( pstrInput.Substring ( intSkipOverMatchedCharacters , DATE_TOKEN_LENGTH ) ); psbOut.Append ( SpecialCharacters.COMMA ); psbOut.Append ( pstrInput.Substring ( intSkipOverMatchedCharacters + DATE_TOKEN_SKIP_CHARS ) ); int rintSearchResumePosition = pintMatchPosition + ( _fIsFirstPass ? FIRST_ITEM_BREAK_POST.Length : SUBSEQUENT_ITEM_BREAK_POST.Length ); _fIsFirstPass = false; // Putting this here allows execution to be unconditional. return ArrayInfo.OrdinalFromIndex ( rintSearchResumePosition ); } // private int FixThisItem
} // public string GetDLLSetting /// <summary> /// Set the like named properties from the linked configuration file. /// </summary> /// <param name="pderivedType"> /// When the derived class constructor calls this method, it must pass in a /// reference to its own Type property. /// </param> /// <returns> /// The return value is the count of properties that were set. /// </returns> /// <remarks> /// This can almost certainly be simplified by enumerating the settings, /// but either way risks a NOT FOUND exception. /// /// This method uses some fairly tricky Reflection gymnastics to map the /// key names in a configuration file to property names on an object. /// </remarks> protected PropertySourceCounts SetPropertiesFromDLLConfiguration ( Type pderivedType ) { const BindingFlags BASELINE_BINDING_FLAGS = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; PropertySourceCounts rutpCounts = new PropertySourceCounts ( ); rutpCounts.Defaulted = MagicNumbers.ZERO; rutpCounts.SpecifiedInConfiguration = MagicNumbers.ZERO; string [ ] astrDefaultErrorMessageColors = DLLSettings.AllKeys; for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < astrDefaultErrorMessageColors.Length ; intJ++ ) { string strPropertyName = null; // This must be visible to the catch block. try { strPropertyName = astrDefaultErrorMessageColors [ intJ ]; string strConfigValueString = DLLSettings [ strPropertyName ].Value; TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( @"At iteration {0} in {1}: {2} = {3}" , // Format control string new object [ ] // Array of values to substitute for tokens in format control string { ArrayInfo.OrdinalFromIndex ( intJ ) , // Format Item 0: At iteration {0} MethodBase.GetCurrentMethod ( ).Name , // Format Item 1: in {1} strPropertyName , // Format Item 2: : {2} strConfigValueString // Format Item 3: = {3} } ) ); PropertyInfo piThisProperty = this.GetType ( ).GetProperty ( strPropertyName , // string name = The string containing the name of the property to get BASELINE_BINDING_FLAGS ); // bindingAttr BindingFlags = A bitmask comprised of one or more BindingFlags that specify how the search is conducted if ( piThisProperty != null ) { piThisProperty.SetValue ( this , // Object obj = Object to which to apply setting FromString ( piThisProperty , strConfigValueString ) , // Object value = Value to assign to the property to which piThisProperty refers BASELINE_BINDING_FLAGS | BindingFlags.SetProperty , // invokeAttr invokeAtt = A bitwise combination of the following enumeration members that specify the invocation attribute: InvokeMethod, reateInstance, Static, GetField, SetField, GetProperty, or SetProperty. You must specify a suitable invocation attribute. null , // Binder binder = An object that enables the binding, coercion of argument types, invocation of members, and retrieval of MemberInfo objects through reflection. If binder is null, the default binder is used. null , // Object[] index = Optional index values for indexed properties. This value should be null for non-indexed properties. null ); // CultureInfo culture = The culture for which the resource is to be localized. If the resource is not localized for this culture, the Parent property will be called successively in search of a match. If this value is null, the culture-specific information is obtained from the CurrentUICulture property. rutpCounts.SpecifiedInConfiguration++; // Count properties successfully set; the final value is returned as the function value. } // TRUE (The configuration file has a value for this property.) block, if ( piThisProperty != null ) else { MissingConfigSettings = MissingConfigSettings ?? UnconfiguredDLLSettings.TheOnlyInstance; MissingConfigSettings.Add ( Path.GetFileName ( _strAssemblyLocation ) , strPropertyName , // Format Item 0: property {1} default value strConfigValueString ); // Format Item 1: default value of {2} accepted rutpCounts.Defaulted++; // Count properties that retained their hard coded default values. } // FALSE (A value for this property is absent from the configuration file.) block, if ( piThisProperty != null ) } catch ( Exception exAllKinds ) { // Since the catch block is within the body of the For loop, processing advances to the next item. TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( @"{0}.{1} = {2}" , nameof ( Environment ) , nameof ( Environment.StackTrace ) , Environment.StackTrace ) ); if ( RecoveredConfigurationExceptions == null ) { // Create as and when needed. RecoveredConfigurationExceptions = new System.Collections.Generic.List<RecoveredException> ( ); } // if ( RecoveredConfigurationExceptions == null ) RecoveredConfigurationExceptions.Add ( new RecoveredException ( string.Format ( Properties.Resources.ERRMSG_EXCEPTION_NOT_THROWN , SaveErrorReport ( this.GetType ( ) , strPropertyName , exAllKinds ).Message ) , exAllKinds.Source , exAllKinds.StackTrace , exAllKinds.TargetSite.Name ) ); Exception exWrapped = RecoveredConfigurationExceptions [ ArrayInfo.IndexFromOrdinal ( RecoveredConfigurationExceptions.Count ) ]; TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_1 , exWrapped.Message ) ); TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_2 , exWrapped.Source ?? Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_3 , exWrapped.TargetSite != null ? exWrapped.TargetSite.Name : Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_4 , exWrapped.StackTrace ?? Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); // -------------------------------------------------------- // Since SaveErrorReport appends the inner exception, this // test is technically redundant, but I chose to leave it, // as a reminder that new exceptions are not necessarily // so decordated. Hence, with the test, this code is a bit // more portable. // -------------------------------------------------------- if ( exWrapped.InnerException != null ) { TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_5 , exWrapped.InnerException.Message ?? Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_6 , exWrapped.InnerException.Source ?? Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_7 , exWrapped.InnerException.TargetSite.Name ?? Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); TraceLogger.WriteWithBothTimesLabeledLocalFirst ( string.Format ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_8 , exWrapped.InnerException.StackTrace ?? Common.Properties.Resources.MSG_OBJECT_REFERENCE_IS_NULL ) ); } // TRUE (anticipated outcome) block, if ( exWrapped.InnerException != null ) else { TraceLogger.WriteWithBothTimesLabeledLocalFirst ( Properties.Resources.TRACEMSG_EXCEPTION_NOT_THROWN_9 ); } // FALSE (unanticipated outcome) block, if ( exWrapped.InnerException != null ) } // catch ( Exception exAllKinds ) } // for ( int intJ = ArrayInfo.ARRAY_FIRST_ELEMENT ; intJ < astrDefaultErrorMessageColors.Length ; intJ++ ) return rutpCounts; } // SetPropertiesFromDLLConfiguration
} // ListPropertiesPerDefaultToString method (3 of 4) /// <summary> /// Format names and values of the properties reported by the ToString /// method on any object for rendering on a report, such as the console /// display of a character-mode application. /// </summary> /// <param name="pobjToList"> /// Pass in a reference to the object of interest. Its ToString method, /// presumably a custom (overrridden) method is called, and the string /// that it returns is parsed and formatted. /// /// Its ToString method is expected to return a string that begins with /// the object's internal name (type), followed by a colon and a list of /// properties. Each property is expected to be listed as a name-value /// pair, with the name and its value sapearated by an equals sign, and /// properties delimited by either a single character, such as a comma, /// or the platform-dependent newline sequence, e. g., CR/LF for Windows /// or LF for Linux. /// </param> /// <param name="pchrDelimiter"> /// Pass in the single-character delimiter that separates property names /// and their values from each other. To specify that the pairs are /// delimited by newlines, specify SpecialCharacters.NULL_CHAR, the NULL /// (numeric value zero) character. /// </param> /// <param name="pintAdditionalPaddingChars"> /// Specify the number of characters of extra white space, if any, to be /// prepended to subsequent output lines to cause the report to aligne /// vertically. This is useful when the format string through which it /// will be written contains text that precedes the output string, which /// would otherwise cause subsequent detail lines to be misaligned. /// </param> /// <returns> /// The return value is a string that can be fed through a standard /// format item to string.Format, Console.WriteLine, or any of their /// cousins. /// </returns> public static string ListPropertiesPerDefaultToString ( object pobjToList , char pchrDelimiter , int pintAdditionalPaddingChars ) { const string THIRD_FORMAT_ITEM = @" {2}{3}"; StringBuilder rsb = null; string [ ] astrProperties = null; astrProperties = pchrDelimiter == SpecialCharacters.NULL_CHAR ? WizardWrx.EmbeddedTextFile.Readers.StringOfLinesToArray ( pobjToList.ToString ( ) ) : pobjToList.ToString ( ).Split ( pchrDelimiter ); LabelAndValue [ ] autpLabelAndValue = new LabelAndValue [ astrProperties.Length ]; string strTypeName = null; // The string.IsNullOrEmpty method requires an initialized argument. for ( int intIndex = ArrayInfo.ARRAY_FIRST_ELEMENT ; intIndex < astrProperties.Length ; intIndex++ ) { string [ ] astrLabelAndItsValue = null; if ( intIndex == ArrayInfo.ARRAY_FIRST_ELEMENT ) { // The first item contains also the property type name, followed by a colon and a space. int intPosColon = astrProperties [ intIndex ].IndexOf ( SpecialCharacters.COLON ); int intPosNext = intPosColon + ArrayInfo.NEXT_INDEX; // ------------------------------------------------ // As always, use a belt and suspenders, covering // the chance that the first label immediately // follows the colon that delimits it from the // object type name. // // Whether the break occurs at the colon or the // immediately following space, the position is set // such that the last charecter goes into the type // name field, leaving the remainder of the string // to be divided into the propertry value and its // label. // ------------------------------------------------ int intPosBreak = ArrayInfo.OrdinalFromIndex ( astrProperties [ intIndex ] [ intPosNext ] == SpecialCharacters.SPACE_CHAR ? intPosNext : intPosColon ); strTypeName = astrProperties [ intIndex ].Substring ( ListInfo.SUBSTR_BEGINNING , intPosBreak ); astrLabelAndItsValue = astrProperties [ intIndex ].Substring ( intPosBreak ).Split ( SpecialCharacters.EQUALS_SIGN ); } // TRUE (This iteration processess the first property item.) block, if ( intIndex == ArrayInfo.ARRAY_FIRST_ELEMENT ) else { astrLabelAndItsValue = astrProperties [ intIndex ].Split ( SpecialCharacters.EQUALS_SIGN ); } // FALSE (This iteration processes a subsequent property item.) block, if ( intIndex == ArrayInfo.ARRAY_FIRST_ELEMENT ) autpLabelAndValue [ intIndex ].Label = astrLabelAndItsValue [ ArrayInfo.ARRAY_FIRST_ELEMENT ].Trim ( ); autpLabelAndValue [ intIndex ].Value = astrLabelAndItsValue [ ArrayInfo.ARRAY_SECOND_ELEMENT ].Trim ( ); } // for ( int intIndex = ArrayInfo.ARRAY_FIRST_ELEMENT ; intIndex < astrProperties.Length ; intIndex++ ) // -------------------------------------------------------- // Compute the length of the longest label string, so that // a format string that renders the labels and their values // in a neatly aligned list can be constructed. // -------------------------------------------------------- int intLabelFieldWidth = ComputeLabelFieldWidth ( autpLabelAndValue ); string strPropertyPadding = SpecialStrings.EMPTY_STRING.PadRight ( strTypeName.Length ); // -------------------------------------------------------- // A string is constructed with two right-padded format // items and a third and fourth default format items. // // 1) The first format item gets the type name string, // strTypeName, on the first iteration of a loop over // the autpLabelAndValue array, while subsequent // iterations use the strPropertyPadding string. // // 2) The second format item gets the property name from // the Label member of a LabelAndValue structure stored // in the current element of the autpLabelAndValue // array. // // 3) The third format item gets the Value member of the // LabelAndValue structure stored in the current // element of the autpLabelAndValue array. // // 4) The fourth format item gets the platform-specific // newline character or sequence thereof. // -------------------------------------------------------- string strDynamicFormatString = string.Concat ( new string [ ] { FormatItem.AdjustToMaximumWidth ( ArrayInfo.ARRAY_FIRST_ELEMENT , strTypeName.Length , FormatItem.Alignment.Left , SpecialStrings.EMPTY_STRING ) , SpecialCharacters.SPACE_CHAR.ToString ( ) , FormatItem.AdjustToMaximumWidth ( ArrayInfo.ARRAY_SECOND_ELEMENT , intLabelFieldWidth , FormatItem.Alignment.Left , SpecialStrings.EMPTY_STRING ) , THIRD_FORMAT_ITEM } ); // -------------------------------------------------------- // The initial capacity of the StringBuilder is twice the // label width plus the length of the type name, times the // number of label/value pairs in the autpLabelAndValue // array. // -------------------------------------------------------- rsb = new StringBuilder ( ( intLabelFieldWidth * MagicNumbers.PLUS_TWO + strTypeName.Length ) * autpLabelAndValue.Length ); for ( int intItemIndex = ArrayInfo.ARRAY_FIRST_ELEMENT ; intItemIndex < autpLabelAndValue.Length ; intItemIndex++ ) { rsb.AppendFormat ( strDynamicFormatString , new string [ ] { intItemIndex == ArrayInfo.ARRAY_FIRST_ELEMENT ? strTypeName : strPropertyPadding , autpLabelAndValue [ intItemIndex ].Label , autpLabelAndValue [ intItemIndex ].Value , Environment.NewLine } ); // ------------------------------------------------------------ // Unless pintAdditionalPaddingChars is zero, the first pass // generates a new format control string that allows more // characters to its first format item. // ------------------------------------------------------------ if ( pintAdditionalPaddingChars > ListInfo.EMPTY_STRING_LENGTH && intItemIndex == ArrayInfo.ARRAY_FIRST_ELEMENT ) { strDynamicFormatString = string.Concat ( new string [ ] { FormatItem.AdjustToMaximumWidth ( ArrayInfo.ARRAY_FIRST_ELEMENT , strTypeName.Length + pintAdditionalPaddingChars , FormatItem.Alignment.Left , SpecialStrings.EMPTY_STRING ) , SpecialCharacters.SPACE_CHAR.ToString ( ) , FormatItem.AdjustToMaximumWidth ( ArrayInfo.ARRAY_SECOND_ELEMENT , intLabelFieldWidth , FormatItem.Alignment.Left , SpecialStrings.EMPTY_STRING ) , THIRD_FORMAT_ITEM } ); } // if ( pintAdditionalPaddingChars > ListInfo.EMPTY_STRING_LENGTH && intItemIndex == ArrayInfo.ARRAY_FIRST_ELEMENT ) } // for ( int intItemIndex = ArrayInfo.ARRAY_FIRST_ELEMENT ; intItemIndex < autpLabelAndValue.Length ; intItemIndex++ ) return rsb.ToString ( ); } // ListPropertiesPerDefaultToString method (4 of 4)