YCOE

You Can't stOp mE!

前几天,在写一个自动从XML中读取数值并注入到对象属性中去的时候,为了方便,不想把原来是int类型的写与string类型,但是从XML里读取出来的时候,都是string类型。这时就需要将string类型自动地根据对象属性的类型转换过来。

比如string ==> int/long/double/DateTime/enum/String/bool....

刚开始的时候,确实有点犯傻,来个长长的switch。

但是突然间想到,在使用asp.net mvc的时候,它们不是也把从表单或URL中传上来的值自动转换成对应的类型了吗?

hoho~~~

眼前一亮,就这么整,看看人家怎么做到的。

使用反编译软件Reflector打开System.Web.Mvc(直接在VS2008下右键选择Reflector打开就行了,默认位置在C:\Program Files\Microsoft ASP.NET\ASP.NET MVC 1.0\Assemblies\System.Web.Mvc.dll)

顺着asp.net mvc的访问路径,一路到了下来。发现原来还有一个这么简单的方法,这里直接把我简单的DEMO列出来,相信大家都很容易看明白了:

using System;
using System.ComponentModel;

namespace YcoeXu.Common
{
    
public static class StringExtensions
    {
        
/// <summary>
        
/// 将字符串格式化成指定的数据类型
        
/// </summary>
        
/// <param name="str"></param>
        
/// <param name="type"></param>
        
/// <returns></returns>
        public static Object Format(this String str, Type type)
        {
            
if (String.IsNullOrEmpty(str))
                
return null;
            
if (type == null)
                
return str;
            
if (type.IsArray)
            {
                Type elementType 
= type.GetElementType();
                String[] strs 
= str.Split(new char[] { ';' });
                Array array 
= Array.CreateInstance(elementType, strs.Length);
                
for (int i = 0, c = strs.Length; i < c; ++i)
                {
                    array.SetValue(ConvertSimpleType(strs[i], elementType), i);
                }
                
return array;
            }
            
return ConvertSimpleType(str,type);
        }

        
private static object ConvertSimpleType(object value, Type destinationType)
        {
            
object returnValue;
            
if ((value == null|| destinationType.IsInstanceOfType(value))
            {
                
return value;
            }
            
string str = value as string;
            
if ((str != null&& (str.Length == 0))
            {
                
return null;
            }
            TypeConverter converter 
= TypeDescriptor.GetConverter(destinationType);
            
bool flag = converter.CanConvertFrom(value.GetType());
            
if (!flag)
            {
                converter 
= TypeDescriptor.GetConverter(value.GetType());
            }
            
if (!flag && !converter.CanConvertTo(destinationType))
            {
                
throw new InvalidOperationException("无法转换成类型:" + value.ToString() + "==>" + destinationType);
            }
            
try
            {
                returnValue 
= flag ? converter.ConvertFrom(nullnull, value) : converter.ConvertTo(nullnull, value, destinationType);
            }
            
catch (Exception e)
            {
                
throw new InvalidOperationException("类型转换出错:" + value.ToString() + "==>" + destinationType, e);
            }
            
return returnValue;
        }
    }
}

 

DEMO:

在配置文件里自定义配置:

1. 在<configSections></configSections>节点内添加节点:

  <section name="XuConfig" type="System.Configuration.NameValueSectionHandler" />

 2. 写配置看起来会是这样的:

    <configSections>
      //..其它代码
      
<section name="XuConfig" type="System.Configuration.NameValueSectionHandler" />
    
</configSections>
    
<XuConfig>
      
<add key="ID" value="123"/>
      
<add key="Name" value="YcoeXu"/>
      
<add key="Roles" value="Member,Admin"/>
    
</XuConfig>

 

 

 写个类自动加载

using System;
using System.Reflection;
using System.Collections.Specialized;
using System.Configuration;
using YcoeXu.Common;

namespace YcoeXu.Test
{
    
public class XuConfig
    {
        
private XuConfig() { }

        
private static XuConfig config = null;

        
private static XuConfig Instance
        {
            
get
            {
                
if (config == null)
                {
                    config 
= new XuConfig();
                    Type type 
= typeof(XuConfig);
                    
//从配置文件里读取XuConfig节点
                    NameValueCollection xuConfig = (NameValueCollection)ConfigurationManager.GetSection("XuConfig");
                    
//根据Key匹配对应的属性
                    foreach (String key in xuConfig.AllKeys)
                    {
                        PropertyInfo pi 
= type.GetProperty(key);
                        
if (pi == null || String.IsNullOrEmpty(xuConfig[key]))
                            
continue;
                        
//自动转换类型并注入值
                        pi.SetValue(config, xuConfig[key].Format(pi.PropertyType), null);
                    }
                }
                
return config;
            }
        }

        
public int ID { setget; }
        
public String Name { setget; }
        
public Role[] Roles { setget; }

        
public void Test()
        {
            Console.WriteLine(XuConfig.Instance.Name);
            Console.WriteLine(XuConfig.Instance.ID);
            
foreach (Role r in XuConfig.Instance.Roles)
            {
                Console.WriteLine(r.ToString());
            }
        }
    }

    
public enum Role
    {
        Guest,
        Member,
        Manager,
        Admin
    }
}

 

注意了,一定要添加一个引用:System.Configuration 

这里对String进行了一些扩展,使它可以直接当成String对象的方法访问了,是不是很方便呢。hoho~~~

项目中的一点点心得,发现网上还没有人放出这种方法,这里就写出来给大家分享下,相信对大家以后进行类似的自动转换或赋值的功能实现会有很大的帮助

好啦,公司貌似又要转向PHP了,上年刚从java转到C#,明年又要转向其它语言了,hoho~~~

引用网友的一句话,做人要像柯南这么有霸气,走到哪里,人就死到哪里 

标签: C#

Feedback

#1楼  回复 引用 查看   

2009-12-02 10:00 by 炭炭      
柯南说过吗? 真相只有一个!

#2楼  回复 引用 查看   

2009-12-02 10:09 by 小师傅      
代码不能展开,lz写完自己也要检查下咯。。。

#3楼  回复 引用 查看   

2009-12-02 10:09 by ejiyuan      
简单数据类型 转换 搞的太复杂 其实微软已经有了,你按下面的方法调用下看看。 效果不比你写的差
public T ChangeStringToType<T>(String value)
{
return (T)Convert.ChangeType(value, typeof(T));
}

#4楼[楼主]  回复 引用 查看   

2009-12-02 10:12 by YCOE      
引用小师傅:代码不能展开,lz写完自己也要检查下咯。。。

刷新下试试,我之前用Chrome编辑的,发现有问题,现在用IE重新编辑过了,默认没收起来了

#5楼  回复 引用   

2009-12-02 10:15 by abli[未注册用户]
干吗在啊?又在造轮子,Convert.ChangeType()方法啊,微软都写玩了,你干嘛又整一个一模一样滴

#6楼[楼主]  回复 引用 查看   

2009-12-02 10:21 by YCOE      
引用abli:干吗在啊?又在造轮子,Convert.ChangeType()方法啊,微软都写玩了,你干嘛又整一个一模一样滴

是耶,我还不知道呢,不过干嘛微软也自己造轮子的,我也说了这是我从asp.net mvc中源码中提取的

#7楼  回复 引用   

2009-12-02 10:24 by 兰缪内衣[未注册用户]
Convert.ChangeType()有了

#8楼  回复 引用 查看   

2009-12-02 10:26 by eaglet      
我也造过一次轮子
http://www.cnblogs.com/eaglet/archive/2009/06/05/1496697.html

#9楼  回复 引用   

2009-12-02 10:55 by W.SiMin[未注册用户]
那不就是序列化和反序列化么?

#10楼  回复 引用 查看   

2009-12-02 12:08 by 斯克迪亚      
我觉得这个场景用XML序列化更直接啊,或者直接用配置文件(.settings)

#11楼  回复 引用 查看   

2009-12-02 13:27 by CoolCode      
@YCOE
应该是为了方便使用者自定义Converter

#12楼  回复 引用 查看   

2009-12-02 15:50 by 代码乱了      
你有没有考虑可空类型Nullable的转换情况

#13楼  回复 引用   

2009-12-03 06:13 by Davy~~[未注册用户]
ASP.NET MVC是 Open Source的,不用祭出Reflector

#14楼  回复 引用 查看   

2009-12-18 12:43 by 丐帮弟子      
楼主的比 Convert.ChangeType() 更胜一筹! 支持数组. 但内定以 ‘;’ 为分隔, 若数组元素本身就有‘;’, 则 …