個人檔案Blogs部落格清單 工具 說明

部落格


3月1日

How refactoring can improve the comprehensibility of source code.

These examples show two kinds of the same code that speak for itself:

 

Figure 1

  static class Program 
  { 
    public static string[] Args = null
       /// <summary> 
    /// The main entry point for the application. 
    /// </summary> 
    [STAThread
    static void Main(string[] args) 
    { 
      if (Properties.Settings.Default.DebugLog) 
      { 
        /// Copy all Trace and Debug reports to columnAttrib file: 
        /// 
        string file = Properties.Settings.Default.DebugFile; 
        FileStream stream = new FileStream(file, FileMode.Create); 
        stream.Close(); 
        stream.Dispose();
        TextWriterTraceListener listener = new TextWriterTraceListener(file); 
        Trace.Listeners.Add(listener); 
        Trace.AutoFlush = true
        Debug.Listeners.Add(listener); 
        Debug.AutoFlush = true
      } 
   
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
   
      foreach (string s in args) 
      { 
        if (s.StartsWith("-locale:", StringComparison.OrdinalIgnoreCase)) 
        { 
          string culture = s.Remove(0, 8); 
          System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(culture); 
        } 
      } 
   
      Args = args; 
      AppLauncher launcher = new AppLauncher(); 
      launcher.Run(args); 
    } 
  }


Figure 2

  static class Program 
  { 
    public static string[] Args = null
   
    /// <summary> 
    /// The main entry point for the application. 
    /// </summary> 
    [STAThread] 
    static void Main(string[] args) 
    { 
      PreprareToLogDebugMessages(); 
   
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
   
      SetCultureFromParams(args); 
      Args = args; 
      AppLauncher launcher = new AppLauncher(); 
      launcher.Run(args); 
    } 
   
    /// <summary> 
    /// If Specified in the Properites Settings, all Debug and Trace outputs are 
    /// redirected to a file. 
    /// </summary> 
    private static void PreprareToLogDebugMessages() 
    { 
      if (Properties.Settings.Default.DebugLog) 
      { 
        /// Copy all Trace and Debug reports to columnAttrib file: 
        /// 
        string file = Properties.Settings.Default.DebugFile; 
        FileStream stream = new FileStream(file, FileMode.Create); 
        stream.Close(); 
        stream.Dispose();
        TextWriterTraceListener listener = new TextWriterTraceListener(file); 
        Trace.Listeners.Add(listener); 
        Trace.AutoFlush = true
        Debug.Listeners.Add(listener); 
        Debug.AutoFlush = true
      } 
    } 
   
    /// <summary> 
    /// Sets the culture for the application if specified by the args. 
    /// </summary> 
    /// <param name="args"></param> 
    private static void SetCultureFromParams(string[] args) 
    { 
      foreach (string s in args) 
      { 
        if (s.StartsWith("-locale:", StringComparison.OrdinalIgnoreCase)) 
        { 
          string culture = s.Remove(0, 8); 
          System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(culture); 
        } 
      } 
    } 
  } 
 

As you see in these code snippets, figure 1 looks very complicated because it's one long function that do various sub parts.

 

In contrast figure 2, although it contains more individual functions, it's easier to understand the meaning of the code, and as a side effect, as logical function parts are separated to a method, you can create an xml header and describe the functionality of the sub part which can be used later for automatic documentating.

11月17日

The Secret of the BindingList

.NET 2.0 knows many variations to collect data. The most familiar way is to use a List class, or what is more efficient a generic List class. With .NET you can also easily assign any kind of ICollections, which is an ancestor of IList to many visual controls like the ListView class or the DataGridView without the need t o write code to add each item to the control or to show the data. In most cases, reflections does this for you. But if you assign a List class to a control, the control is not aware of changes to the list, so what you need to do is to actualize each control that is bound to a List when the list got modified. Now this is the point when the BindingList class becomes interesting:

The BindingList differes from the List in such way, that it notifies every control that is bound to the list that the List has modified. The correlated IBindingList interface introduces the OnListChangedEvent that occurs whenever a change was made to the list and thus the controls, that add an event handler when the get assigned to the BindingList, become aware of changes to the list, without the need of the developer to implement code to take care of it.

To speed up the performance, the generic BindingList supports the functionality to temporarily disable to broadcast OnListChangedEvent when the list gets modified. This makes sense when you start to make wide ranges of modification to the list. Whilst doing this, every single change would fire a ListChangedEvent and every control bound to the list what actualize it's state, which could become time consuming. But If you temporarily disable the event by setting the RaiseListChangedEvent to false, any modification on the list is done WITHOUT raising a ListChangedEvent. But you mustn't forget to execute the ResetBindings method of the BindingList after you set RaiseListChangedEvent to true again, otherwhise the bounded controls would not be actualized.

 

Using BindingLists for visual controls is the most frequently usage of it, but you can also use it to inform other none visual classes that depend on the list that a change was made to react on the kind of change. For instance, I'm doing this for the XDTEngine of DOCexplorer, between IXdtFilter and IXdtParser.

 

One disadvantage of the BindingList generic class is, that unlike the generic List class, it does not offer support for sorting. But that's easily to solve. As the BindingList supports methods to get an List copy of all or some elements within the BindingList, you just need to create a temporarily copy of the BindingList, sort the List copy and than finally copy the List back to the BindingList. To easy this procedure, I wrote a special SortableBindingList class that offers the missing sorting support by doing this functionality as described.

 

9月27日

Compiling and running a dynamic method at runtime

This issue might be very useful, for instance if you need to perform an expression for each item in a list, that is depending on the user's input. instead of writing a static method, that is handling all possibilites with conditions like
"if (flag_set) {}", it's possible to dynamically create a small C# source code that is optimized for that special purpose, compile it and simply use it whilst enumerating the list.

the following link shows the way:
http://www.codeproject.com/cs/algorithms/matheval.asp


9月22日

Compression and Decompression

For compressing/decompressing purposes of bytes, .NET 2.0 offers functionality for it.
You can either use the DeflateStream class or the GZipStream class, both available in the
System.IO.Compression assembly. See the MSDN for further information.