利用 TypeConverter,转换字符串和各种类型只需写一个函数
本文代码基于 .NET Framework 实现。
本来只想进行简单的配置存储的,不料发现 .NET 的基本类型多达十多种。于是,如果写成下面这样,那代码可就太多了哦:
// 注:`Configurator`是我的配置类,用于读写字符串的。
public static int GetInt32(this Configurator config, string key)
{
return int.Parse(config[key], CultureInfo.InvariantCulture);
}
public static void SetInt32(this Configurator config, string key, int value)
{
config[key] = value.ToString(CultureInfo.InvariantCulture);
}
public static bool GetBoolean(this Configurator config, string key)
{
return bool.Parse(config[key]);
}
// 还没完,这才 1.5 种而已。
// ……
尝试使用泛型
这些方法都比较相似,于是自然而然想到了泛型,所以写出了这段代码:
public static T GetValue<T>(this Configurator config, string key) where T : struct
{
var @string = config[key];
// T value = 某种通用的转换(@string); // 问题来了,这里该怎么写?
return value;
}
这里就郁闷了,因为虽然方法内部的实现都长得差不多,但他们之间除了名字相同之外(比如 Parse和ToString),并没有什么联系;这样,便不能使用统一的接口或者抽象类等等来调用。
尝试使用反射
既然名字类似,那自然又能想到反射。可是,拥有 Parse 的类型并不多,ToString 中能传入 CultureInfo.InvariantCulture 且参数顺序保持一致的类型也少的可怜。于是,反射只能保证写得出来代码,却并不能保证多种类型的支持。
另外想到一点,Int32 类型的 TryParse 中有 out 关键字修饰的参数,反射能否支持呢?StackOverflow 上找到了答案:
You invoke a method with an out parameter via reflection just like any other method. The difference is that the returned value will be copied back into the parameter array so you can access it from the calling function.
object[] args = new object[] { address, request };
_DownloadDataInternal.Invoke(this, args);
request = (WebRequest)args[1];
意思是说,这在反射中不用作什么考虑,传入的参数数组天然就已经支持了 out 关键字。
尝试寻找更通用的方案
在 Google 上继续漫游,在 StackOverflow 上发现这篇讨论:How to convert string to any type。
最高票答案给出的回复是:
using System.ComponentModel; TypeConverter typeConverter = TypeDescriptor.GetConverter(propType);
object propValue = typeConverter.ConvertFromString(inputValue);
这可打开了思路,原来 .NET Framework 内部已经有了这种转换机制和相关的方法。于是用这种方法修改我的方法,成了这样子:
public static T GetValue<T>(this Configurator config, string key) where T : struct
{
var @string = config[key];
var td = TypeDescriptor.GetConverter(typeof (T));
return (T) td.ConvertFromInvariantString(@string);
}
public static void SetValue<T>(this Configurator config, string key, T value) where T : struct
{
var td = TypeDescriptor.GetConverter(typeof (T));
var @string = td.ConvertToInvariantString(value);
config[key] = @string;
}
编写单元测试发现,这种方法能够支持的类型真的非常多,byte char short ushort int uint long ulong bool float double decimal DateTime Point Vector Size Rect Matrix Color……
看看代码中 TypeDescriptor.GetConverter 的返回值发现是 TypeConverter 类型的,而我们在 WPF 的 xaml 中编写自定义类型时,经常需要执行此类型的 TypeConverter。凭这一点可以大胆猜测,xaml 中能够通过字符串编写的类型均可以通过这种方式进行转换。然而,目前我还为对此进行验证。
验证猜想
- 去 https://referencesource.microsoft.com/ 看
TypeDescriptor.GetConverter的源码(点击进入)。 - 尝试自定义一个类型,在类型上标记
TypeConverter,并对此类进行测试。
利用 TypeConverter,转换字符串和各种类型只需写一个函数的更多相关文章
- linux上怎么切换不同版本的arm-linux-gcc?只需改一行函数
linux上怎么切换不同版本的arm-linux-gcc?只需改一行函数 ln -s /usr/local/arm/3.4.1/bin/arm-linux-gcc /usr/bin/arm-linux ...
- 【C语言】写一个函数,实现字符串内单词逆序
//写一个函数,实现字符串内单词逆序 //比如student a am i.逆序后i am a student. #include <stdio.h> #include <strin ...
- RecyclerView.Adapter封装,最简单实用的BaseRecyclerViewAdapter;只需重写一个方法,设置数据链式调用;
之前对ListView的BaseAdapter进行过封装,只需重写一个getView方法: 现在慢慢的RecyclerView成为主流,下面是RecyclerView.Adapter的封装: Base ...
- 38 写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度。
题目:写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度. public class _038PrintLength { public static void main(Stri ...
- 写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度
import java.util.Scanner; /** * [程序38] * * 题目:写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度. * * @author Jame ...
- 写一个函数,输入int型,返回整数逆序后的字符串
刚刚看到一个面试题:写一个函数,输入int型,返回整数逆序后的字符串.如:输入123,返回"321". 要求必须用递归,不能用全局变量,输入必须是一个參数.必须返回字符串.&quo ...
- C++ 利用指针和数组以及指针和结构体实现一个函数返回多个值
C++ 利用指针和数组实现一个函数返回多个值demo1 #include <iostream> using namespace std; int* test(int,int,int); i ...
- 写一个函数,实现两个字符串的比较。即实现strcmp函数,s1=s2时返回0,s1!=s2时返回二者第一个不同字符的ASCII值。
#include<stdio.h> #include<stdlib.h> int main(){ setvbuf(stdout,NULL,_IONBF,); ],s2[]; i ...
- Java实现汉诺塔移动,只需传一个int值(汉诺塔的阶)
public class HNT { public static void main(String[] args) { HNT a1 = new HNT(); a1.lToR(10); //给汉诺塔a ...
随机推荐
- Android -- 文件上传到服务器
1. 文件上传的两种方式 (1) HttpClient (2)AsyncHttpClient (开源框架: https://github.com/loopj/android-async-http) 示 ...
- Memcached gets 命令
Memcached gets 命令获取带有 CAS 令牌存 的 value(数据值) ,如果 key 不存在,则返回空. 语法: gets 命令的基本语法格式如下: gets key 多个 key 使 ...
- cassandra 之 在spark-shell 中使用 spark cassandra connector 完整案例
1.cassandra 准备 启动cqlsh, CQLSH_HOST=172.16.163.131 bin/cqlsh cqlsh>CREATE KEYSPACE productlogs WIT ...
- C++(三十三) — 全局函数、成员函数的区别
区别: (1)全局函数的参数个数,比局部函数要多一个: (2)二者都可,返回元素.返回引用. class test { public: test(int a, int b) { this->a ...
- 1059: [ZJOI2007]矩阵游戏 二分图匹配
https://www.lydsy.com/JudgeOnline/problem.php?id=1059 裸的二分图匹配,行列匹配即可 /****************************** ...
- 各种数据库对应的jar包、驱动类名和URL格式
1.1. 各种数据库对应的jar包 具体如下: 数据库类型 对应的Jar文件 Oracle 8i classes12.zip 或 ojdbc14.jar Sybase jconn2.jar ...
- day5-logging模块
一.概述 好的程序开发,往往会兼顾到日志输出的需求,以便给用户提供必要的日志信息便于确认程序运行状态.排错等等.这些日志一般包括程序的正常运行日志.访问日志.错误日志.数据保存日志等类型.在pytho ...
- SqlServer 转 Oracle 的几点注意
(转自:http://www.2cto.com/database/201208/146740.html) 1.字符型的字段相加需要用“||”,如果用“+”的话,会报“无效的数字”的错误. 2.类似 ...
- Django-自定义分页组件
1.封装的分页代码: class PageInfo(object): def __init__(self,current_page,all_count,per_page,base_url,show_p ...
- 【转】netlink socket编程实例
[转]netlink socket编程实例 转自:http://blog.chinaunix.net/uid-14753126-id-2983915.html 关于Netlink IPC方式的介绍,请 ...