C# Small Tips

學習和使用C#這麼久,也有了些可以跟大家分享的經驗和教訓,這裏分享下幾個關於C#開發的小技巧:

1. 輸出變量的名稱。

    需求:有時候我們在測試或平時練習的時候可能想把變量的值和它自身的名稱一起輸入到屏幕或者其他地方,而不是自己在代碼中寫變量名。如:

    var A = 10;

    Console.WriteLine("Var Name:A,Value:{0}", A);

    實現:實現這個功能有兩種方式。讀者不妨也思考一下有沒有其他更好的方式實現這個功能。

        a. 我首先給出通過匿名類型和反射的實現方式。

    public static class ObjectExtensions
    {
        
public static string GetVariableName<T>(this T obj)
        {
            System.Reflection.PropertyInfo[] objGetTypeGetProperties 
= obj.GetType().GetProperties();

            
if (objGetTypeGetProperties.Length == 1)
                
return objGetTypeGetProperties[0].Name;
            
else
                
throw new ArgumentException("object must contain one property");
        }
     }

    
//調用方式,我們通過匿名類型構造對象,然後通過反射獲取它內部屬性
     static void main()
     {
            
string testVar1 = "testName";
            Console.WriteLine(
new { testVar1 }.GetVariableName());

            
int testVar2 = 12345;
            Console.WriteLine(
new { testVar2 }.GetVariableName());
     }

    b. 通過.NET 3 中的Lamda表達式這裏給出另外一個更加方便的實現方式。

  static void WriteName<T>(Expression<Func<T>> expression)
  {
       Console.WriteLine(
"{0}={1}",
                ((MemberExpression)expression.Body).Member.Name,
                expression.Compile()());
  }
  static void main()
  {
       
string testVar1 = "testName";
        WriteName(() 
=> testVar1);
  }

2. 字符串轉換爲基本類型

    需求:在日常編程中,我們經常要在文件或用戶輸入界面中將一些字符串變量轉換爲常用類型,當然我們可以用System.Convert類來完成這項工作,但如果有大量轉換工作進行的時候,這種代碼看起來很不方便,這時候我們可以通過.net的一些新的特性來很方便的完成這項工作

    實現:通過擴展方法,反射和泛型可以很方便完成這項工作。

    public static class ObjectExtensions
    {
        
static T? To<T>(this string parse)
            
where T : struct
        {
            Type t 
= typeof(T);
            
if (t == typeof(int))
            {
                
int i;
                
if (int.TryParse(parse, out i))
                    
return (T)(object)i;
                
return null;
            }
            
if (t == typeof(double))
            {
                
double i;
                
if (double.TryParse(parse, out i))
                    
return (T)(object)i;
                
return null;
            }
            
//添加其他類型的轉換代碼,如DateTime,Enum,etc;
            throw new NotSupportedException(string.Format("類型:{0}轉換不支持",t.Name));
        }
     }
     
//使用函數
     static void main()
     {
       
int? a="111".To<int>();
        
double? b="111.111".To<double>();
        
int? c="bad".To<int>();
     }

不過這個轉換代碼中由於有兩個類型轉換才能通過編譯,所以看起來仍然沒那麼舒服,希望大家能有更好的方式實現。

3. WinForm編程中線程安全調用組件。

    需求:在.net 1.0的時候在其他線程中操作Win Form 主線程組件時候是可以直接操作的,但這也帶來了潛在的風險。於是在2.0以後跨線程操作你需要通過BeginInvoke來完成該項操作,但這也讓代碼看起來很拖沓,有時用戶可能僅僅只需要在線程某項操作完成後僅僅更新窗口中的某個組件,如進度條而已,卻需要另外寫一個函數去實現。

    實現: 拖過擴展函數和匿名方法可以很方便的完成窗口線程和其他線程之間的交互工作。下面給出了一個簡單的實現,當然,如果你需要更安全的調用,還需要添加一些檢測,如IsHandleCreated檢測,另外如果你需要傳遞參數,你可能需要另外定義一個委託.

    public static class ControlExtention
    {
        
public delegate void InvokeHandler();

        
public static void SafeInvoke(this Control control, InvokeHandler handler)
        {
            
if (control.InvokeRequired)
            {
                control.Invoke(handler);
            }
            
else
            {
                handler();
            }
        }
    }

   
//在form中當用戶在非form線程中需要操作form中組件對象時,調用如下
    public form:Form
    {
     
public form()
      {
        Thread t
=new  Thread(t1);
        t.start();
      }
     
void t1()
      {
            Thread.Sleep(
1000);
            
this.SafeInvoke(() => this.textBox1.Text = "Hello world");
      }
    }

那麼在WPF中能否像上面那樣調用該方法呢? 由於WPF中Invoke改爲Dispatcher,因此方法稍有不同,如下:

public static void SafeInvoke(this Control control, InvokeHandler handler)
{
if (control.Dispatcher.CheckAccess())
{
// The calling thread owns the dispatcher, and hence the UI element
handler();
}
else
{
// Invokation required
control.Dispatcher.Invoke(DispatcherPriority.Normal, handler);
}
}

上面只是平時碰到或者從別人那裏學到的一些小的編程技巧,希望能對其他人也有所幫助。有機會的話希望能把我更多的自認爲好的總結髮出來。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章