惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Latest
Security Latest
G
Google Developers Blog
量子位
WordPress大学
WordPress大学
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
大猫的无限游戏
大猫的无限游戏
Apple Machine Learning Research
Apple Machine Learning Research
阮一峰的网络日志
阮一峰的网络日志
S
SegmentFault 最新的问题
Blog — PlanetScale
Blog — PlanetScale
B
Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
P
Proofpoint News Feed
美团技术团队
V
Visual Studio Blog
Last Week in AI
Last Week in AI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
F
Fortinet All Blogs
博客园 - Franky
The Register - Security
The Register - Security
O
OpenAI News
Google DeepMind News
Google DeepMind News
A
Arctic Wolf
罗磊的独立博客
博客园 - 叶小钗
博客园 - 聂微东
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Y
Y Combinator Blog
SecWiki News
SecWiki News
T
Tor Project blog
月光博客
月光博客
S
Secure Thoughts
博客园 - 【当耐特】
Help Net Security
Help Net Security
D
Docker
Recent Announcements
Recent Announcements
GbyAI
GbyAI
B
Blog RSS Feed
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
T
The Blog of Author Tim Ferriss
Webroot Blog
Webroot Blog
V
Vulnerabilities – Threatpost
Forbes - Security
Forbes - Security
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Hacker News: Ask HN
Hacker News: Ask HN
Cyberwarzone
Cyberwarzone
宝玉的分享
宝玉的分享
Cisco Talos Blog
Cisco Talos Blog
I
InfoQ
Microsoft Security Blog
Microsoft Security Blog

博客园 - C#初学者009

脱壳学习 SQL Server表描述 及 字段描述的增、删、改、查询 关于Wind2003下MSDTC对DTS运行的影响 SQL 标识列起始种子重设 C#跨线程操作控件 通过委托处理,MSDN上又很详细用法的说明 - C#初学者009 - 博客园 .net项目开发工具(V3.0 ) asp.net控件开发基础(5) -- 复杂属性、内嵌属性 - C#初学者009 如何用vb设置默认打印机? 如何使用 SetPrinter 修改打印机设置 用vb做的activex控件打包成cab后如何发布呢? VB中利用CopyMemory使用指针 如何用vb(API)代码设置不规则打印纸尺寸? 如何在 Windows NT 和 Windows 2000 中使用自定义页面大小打印(VB) 确定打印机状态和打印工作状态从Visual Basic VB怎么检测打印机状态 - C#初学者009 - 博客园 在.NET中实现对象序列化(转) XmlSerializer 常见问题疑难解答(MSDN) TransactionScope和分布式事务 (转) 对象序列化:使用System.Xml.Serialization命名空间(转)
如何将字符串动态转换为指定的值类型 - C#初学者009 - 博客园
C#初学者009 · 2009-10-29 · via 博客园 - C#初学者009

作者:eaglet

转载请保留原作者署名并注明出处。

      我们日常工作中经常会遇到将字符串转换为值类型的问题,比如"123" 转换为一个Int32类型,这个很简单,我们只要调用int.Parse 函数就可以实现。eaglet 今天要说的是,一些应用中往往在编码阶段无法知道字符串需要转换成的值类型的具体类型,而需要在运行时动态指定类型进行转换,遇到这种问题,我们如何解决?

      一个典型的例子。

      如下函数,我们只知道value 是一个基本值类型,比如(System.Int32, System.Int16, System.Double 等等) 或者是一个字符串类型。但我们无法在编码时确定这个value 具体是什么类型,它可能是由一个外部组件从某个数据源中读出来的基本类型中的一种类型的实例或者是字符串类型实例。

      这个函数希望实现比较value 是否在minValue, maxValue这两个字符串对应的数值区间类,其中minValue 和 maxValue 构成一个闭区间,即

      value in [minValue, maxValue]

      public static bool MyComparer(object value, string minValue, string maxValue)

     要解决这个问题,我们需要解决两个基本问题。

      1. 如何比较value 和 minValue, maxValue

      2. 如何将minValue 和 maxValue 转换到value 对应的数据类型

      首先我们来看如何进行比较

      所有的基本值类型和string 类型都实现 IComparable这个接口。我们可以指定 value 为 IComparable,然后调用CompareTo来进行比较。不过这里有个问题,CompareTo 函数的参数obj 虽然是一个 object 类型,但这个 obj 的类型必须和 value 一致,否则将发生异常。也就是说我们不能把minValue 任意转换成某个类型比如 long 带进去,而需要将 minValue 和 maxValue 转换成和 value 一样的类型才行。

       下面我们就来讨论如何将字符串转换为指定的值类型。

       我们需要实现下面的函数:

       public static object ToType(Type type, string value)

       type 为指定的类型,value 为输入的字符串。

       首先我们知道所有的基本值类型都有一个叫 Parse 静态函数,我们只要把这个静态函数反射出来,就可以通过这个静态函数将字符串转换成对应的值类型。

       下面代码给出如何反射出这个静态函数。通过向对象type(Type类型)的GetMethods 函数输入 BindingFlags.Static 
                
| BindingFlags.Public 参数,我们可以枚举出这个类型所有的静态公共函数。

        然后我们判断这个函数的名称是否为 "Parse" ,由于 Parse 函数有多个重载,但一个参数的重载只有 Parse (String)

        所以我们需要判断mi 只有一个参数,这时取到的 mi 就是 Parse (String) 函数。

            MethodInfo parseMethod = null;

            
foreach (MethodInfo mi in
 type.GetMethods(BindingFlags.Static 
                
|
 BindingFlags.Public))
            
{
                
if (mi.Name == "Parse" && mi.GetParameters().Length == 1
)
                
{
                    parseMethod 
=
 mi;
                    
break
;
                }

            }

      接下来就是如何调用这个函数来转换字符串了。

      如下面代码,我们调用MethodInfo 的 Invoke 方法来动态调用这个函数,由于是静态函数,第一个参数 obj 传入null. 并在第二个参数中带入value 这个参数。

parseMethod.Invoke(nullnew object[] { value });

      下面给出字符串转换为指定类型的完整代码

using System;
using
 System.Collections.Generic;
using
 System.Text;
using
 System.Reflection;

namespace
 Eagelt.Convert
{
    
public class
 ConvertString
    
{
        
public static object ToType(Type type, string
 value)
        
{
            
if (
type == typeof(string))
            
{
                
return
 value;
            }


            MethodInfo parseMethod 
= null;

            
foreach (MethodInfo mi in
 type.GetMethods(BindingFlags.Static 
                
|
 BindingFlags.Public))
            
{
                
if (mi.Name == "Parse" && mi.GetParameters().Length == 1
)
                
{
                    parseMethod 
=
 mi;
                    
break
;
                }

            }


            
if (parseMethod == null)
            
{
                
throw new ArgumentException(string
.Format(
                    
"Type: {0} has not Parse static method!"
, type));
            }


            
return parseMethod.Invoke(nullnew object[] { value });
        }

    }

}

下面这个是根据"流言社"的评论改进的。谢谢"流言社"

    public class ConvertString
    
{
        
public static object ToType(Type type, string
 value)
        
{
            
return
 System.ComponentModel.TypeDescriptor.GetConverter(type).ConvertFrom(value);
        }

    }

 MyComparer 函数的完整代码

        public static bool MyComparer(object value, string minValue, string maxValue)
        
{
            IComparable comparableObj 
= value as
 IComparable;

            
object
 min;
            
object
 max;

            
if (comparableObj == null
)
            
{
                
throw new ArgumentException(string
.Format(
                    
"Type: {0} does not inherit from IComparable"
, value.GetType()));
            }


            min 
= ConvertString.ToType(value.GetType(), minValue);
            max 
=
 ConvertString.ToType(value.GetType(), maxValue);

            
return comparableObj.CompareTo(min) >= 0 && comparableObj.CompareTo(max) <= 0
;

        }

 测试代码

            Console.WriteLine(MyComparer(2"1""3"));
            Console.WriteLine(MyComparer(
3"1""2"
));
            Console.WriteLine(MyComparer((
byte)2"1""3"
));
            Console.WriteLine(MyComparer((
double)3"1""2"
));
            Console.WriteLine(MyComparer(
"3""1""2"));

 测试结果

最后提一个简单的问题,供大家思考,如果我们需要将字符串转换成我们自己定义的复杂类型,如何实现呢?

比如我们有一个结构

struct UInt128

{

public ulong Low;

public ulong High;

}

我们将这个结构的实例对象传入到函数

 Console.WriteLine(MyComparer((UInt128)2"1""3"));

这样可以吗?怎样做才能做到呢?