用字符串来访问对象的属性
项目需要用字符串的形式来访问对象的属性,让我又怀念起"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 { get; set; }
//测试公共静态属性
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"这个类中
可是怎么加好呢?先定下调用方法吧,方法1:emp.GetProperty("EmployeeID"),方法2:Functions.GetProperty(Employee.GetType(),"EmployeeID"),二者之间我毫不犹豫选了前者,关于前者的实现方法我先想到了继承,但是问题有很多,比如:类是单继承的,而且实现的时候GetProperty方法所在的类必须要知道子类的类型,封装性不好,好在.net3.5提供了Extension Methods,下面我们就用它来实现这个需求吧
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 { get; set; }
//测试公共静态属性
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);
}
}
}
}


浙公网安备 33010602011771号