学习和使用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);
}
}

上面只是平时碰到或者从别人那里学到的一些小的编程技巧,希望能对其他人也有所帮助。有机会的话希望能把我更多的自认为好的总结发出来。

posted on 2009-12-19 18:19  jujusharp  阅读(814)  评论(1编辑  收藏  举报