用字符串来访问对象的属性

项目需要用字符串的形式来访问对象的属性,让我又怀念起"DataTable"了,像dt.Rows[0]["EmployeeID"]多爽啊。。。。不过现在.net3.5这么强大,Linq、Lambda Expressions可以方便地对List对象进行筛选、转换所以不应该倒退回DataTable了,既然对象没有这种用字符串型式访问属性的方法,那我们就帮它加上
     可是怎么加好呢?先定下调用方法吧,方法1:emp.GetProperty("EmployeeID"),方法2:Functions.GetProperty(Employee.GetType(),"EmployeeID"),二者之间我毫不犹豫选了前者,关于前者的实现方法我先想到了继承,但是问题有很多,比如:类是单继承的,而且实现的时候GetProperty方法所在的类必须要知道子类的类型,封装性不好,好在.net3.5提供了Extension Methods,下面我们就用它来实现这个需求吧,出于方便考虑,对要读的属性的值不区分大小写,但是这样会带来麻烦,比如Employee对象有"employeeid"和"EmployeeID"两个公共属性,那样的话我目前的解决方法会有问题,不过相信没多少人会这样写对象的属性吧呵呵,代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace WriteLog
{
    
public static class ExtensionMethods
    
{
        
static ExtensionMethods()
        
{
            s_classPropertys 
= new Dictionary<Type, Dictionary<string, PropertyInfo>>();
        }


        
//用来存储所有调用过"GetProperty"方法的对象类型以及它们的属性列表,主要出于性能考虑
        private static Dictionary<Type, Dictionary<string, PropertyInfo>> s_classPropertys;
        
//用于Double Check的辅助对象
        private static object m_classPropertysMutex = new object();

        
/// <summary>
        
/// 得到对象的属性,不区分大小写
        
/// </summary>
        
/// <param name="self"></param>
        
/// <param name="propertyName"></param>
        
/// <returns></returns>

        public static object GetProperty(this object self, string propertyName)
        
{
            
//先看看该对象是否已被缓存到列表中,没有的话新建个,加进去
            if (!s_classPropertys.ContainsKey(self.GetType()))
            
{
                
//线程安全的考虑,来个Double Check
                lock (m_classPropertysMutex)
                
{
                    
if (!s_classPropertys.ContainsKey(self.GetType()))
                    
{
                        
//没有的话新建一个
                        Dictionary<string, PropertyInfo> selfPropertyInfo = new Dictionary<string, PropertyInfo>();
                        
//这里可以根据自己的需要要定制参数,我现在是指定了公共/静态的实例属性,不区分大小写
                        foreach (PropertyInfo p in self.GetType().GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase))
                        
{
                            selfPropertyInfo.Add(p.Name, p);
                        }

                        
//把生成的对象加到缓存对象中
                        s_classPropertys.Add(self.GetType(), selfPropertyInfo);
                    }

                }

            }

            
//到缓存对象中拿该对象的属性列表
            Dictionary<string, PropertyInfo> currentType = s_classPropertys[self.GetType()];

            
//得到要查找的propertyName的propertyInfo
            var propertyInfo = currentType.SingleOrDefault(e => e.Key.ToLower() == propertyName.ToLower()).Value;

            
//如果没有找到,报错之
            if (propertyInfo == null)
                
throw new Exception(self.GetType() + "对象中没有" + propertyName + "的公共属性!");
            
//返回值
            return propertyInfo == null ? null : propertyInfo.GetValue(self, null);

        }


        
//泛型方法,原理同上
        public static T GetProperty<T>(this object self, string propertyName)
        
{
            
return (T)GetProperty(self, propertyName);
        }

    }

    
class Program
    
{
        
/// <summary>
        
/// 待测试的实体类
        
/// </summary>

        class Employee
        
{
            
//测试公共实例属性
            public int EmployeeID getset; }
            
//测试公共静态属性
            public static string Test
            
{
                
get
                
{
                    
return "hasValue";
                }

            }

        }



        
static void Main(string[] args)
        
{
            Employee employee 
= new Employee
            
{
                EmployeeID 
= 1
            }
;

            Console.WriteLine(
"公共实例属性<EmployeeID>为 :" + employee.GetProperty("employeeId"));
            Console.WriteLine(
"公共静态属性<Test>:" + employee.GetProperty("test"));
            
//泛型方法
            Console.WriteLine(employee.GetProperty<int>("employeeId"+ 100);
            
//随便打个字段,让它报错 :)
            try
            
{
                Console.WriteLine(employee.GetProperty(
"asdfsadfsadfasfd"));
            }

            
catch (Exception ex)
            
{
                Console.WriteLine(ex.Message);
            }

        }

    }


}

以上代码只支持.net3.5,主要实现在"ExtensionMethods"这个类中

posted on 2008-05-04 03:51  古宁氧资  阅读(552)  评论(0)    收藏  举报

导航