利用自动类型转换存储string类型

时间:2023-03-10 00:53:33
利用自动类型转换存储string类型

字符串处理是我们最常用的功能,尤其是与其它类型的相互转也会经常使用。

通常情况下我们需要String类型转其它的基础类型。这时我们最常用的是Convert类。
比如:
 Convert.ToInt32("");
Convert.ToDouble("3.4");
Convert.ToDateTime("2014-4-4");

但是这个方法一旦出现转换失败将会非常影响程序的效率。

因此这种方式会更为合理:

 int temp;
bool success= Int32.TryParse("",out temp);
if(!success)
{
temp=;
}

当然这种方式必须输入更多的代码,对于程序员来说有违人性,我也不想一个简单的转换就要输那么一堆代码。

宝宝表示很不高兴,于是定义了一个StringContainer类型以解决类似问题。

 //能够存储基本类型
public void Test1()
{
StringContainer a= ;
StringContainer b="";
StringContainer c=DateTime.Now;
}
//能够自动转换类型
public void Test2(StringContainer d)
{
StringContainer a="";
int b= a + ;
DataTime c=a;
Console.Write(d);
}
//能够调用同一个函数,但参数类型可以不一样
public void Test3()
{
Test2();
Test2(1.2f);
Test2(DateTime.Now);
}

StringContainer类型的精简定义如下,只实现了Int32与String类型的互转:

 public struct StringContainer
{
public static readonly StringContainer Empty=new StringContainer();
public string value;
internal StringContainer(string value)
{
this.value = value;
}
public static implicit operator StringContainer(string value)
{
return new StringContainer(value);
}
public static implicit operator string(StringContainer stringContainar)
{
return stringContainar.value;
}
public static implicit operator Int32(StringContainer stringContainar)
{
Int32 result;
Int32.TryParse(stringContainar.value, out result);
return result;
}
public static implicit operator StringContainer(Int32 obj)
{
return new StringContainer(obj.ToString());
}
}

而其中的StringContainer(string value)函数实现String类型到StringContainer类型的转换。

 public static implicit operator StringContainer(string value)
{
return new StringContainer(value);
}

有了以上函数,我们就可以这样写:

StringContainer str = "23";

其中的Int32函数实现了String类型到Int32类型的自动转换。

 public static implicit operator Int32(StringContainer stringContainar)
{
Int32 result;
Int32.TryParse(stringContainar.value, out result);
return result;
}

通过以上两个函数,我们可以这样写,是不是比Conert类和TryParse函数简单多了?

 StringContainer str = "23";
int num = str;

到底内部是怎样转换的呢?我们从IL上分析代码。

// Method begins at RVA 0x2130
// Code size 20 (0x14)
.maxstack
.locals init (
[] valuetype [NFinal4]System.StringContainer str,
[] int32 num
) IL_0000: nop
IL_0001: ldstr "23"
IL_0006: call valuetype [NFinal4]System.StringContainer [NFinal4]System.StringContainer::op_Implicit(string)
IL_000b: stloc.0
IL_000c: ldloc.0
IL_000d: call int32 [NFinal4]System.StringContainer::op_Implicit(valuetype [NFinal4]System.StringContainer)
IL_0012: stloc.1
IL_0013: ret

1.先将“23”推向栈顶。

2.然后调用以string为参数的初始化函数。

3.把str初始化的结果保存到本地变量中。

4.加载str到栈顶。

5.调用以StringContainer为参数的转换函数。

6.最后把结果存储到本地变量Num中。

从IL代码可以清楚了解。强制类型转换是由C#编译器自动完成的。

也就是说任意类型与StringContainer类型的相互转换是可以通过添加相应的转换函数实现的。

为了支持所有基本类型的相互转换,可以添加StringContainer.tt模板生成相应的类型转换函数。

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
using System; <#var nullableType=new string[]{"String"};#>
<#var structType=new string[]{"SByte","Byte","Int16","UInt16","Int32","UInt32","Int64","UInt64","Boolean","Char","Decimal","Double","Single","DateTime","DateTimeOffset"};#>
namespace System
{
public struct StringContainer
{
public static readonly StringContainer Empty=new StringContainer();
public string value;
internal StringContainer(string value)
{
this.value = value;
}
public override bool Equals(object obj)
{
return base.Equals(obj);
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public static bool operator ==(StringContainer container, string str)
{
return container.value == str;
}
public static bool operator !=(StringContainer container, string str)
{
return container.value != str;
}
<# for(int i=;i<structType.Length;i++){#>
public static implicit operator StringContainer(<#=structType[i]#> obj)
{
return new StringContainer(obj.ToString());
}
<# }#>
<# for(int i=;i<structType.Length;i++){#>
public static implicit operator StringContainer(<#=structType[i]#>? obj)
{
if(obj!=null)
{
return new StringContainer(obj.ToString());
}
return StringContainer.Empty;
}
<# }#>
public static implicit operator StringContainer(string value)
{
return new StringContainer(value);
}
public static implicit operator string(StringContainer stringContainar)
{
return stringContainar.value;
}
<#for(int i=;i<structType.Length;i++){#>
public static implicit operator <#=structType[i]#>(StringContainer stringContainar)
{
<#=structType[i]#> result;
<#=structType[i]#>.TryParse(stringContainar.value, out result);
return result;
}
<#}#>
<#for(int i=;i<structType.Length;i++){#>
public static implicit operator <#=structType[i]#>?(StringContainer stringContainar)
{
<#=structType[i]#> result;
if(<#=structType[i]#>.TryParse(stringContainar.value, out result))
{
return result;
}
else
{
return null;
}
}
<#}#>
}
}

实现这些基本函数后。我们可以这样写:

 StringContainer str="";
int b=str*;
str=DateTime.Now;
str.ToString();
str=4.33;
double? a=str+;

是不是感觉StringContainer有点var变量的味道?而且自带自动转换功能。

在之前的AspNet以及asp.net core中都有一个Context.Request.Form的Collection类型。

我们是否可以改造该类型呢?

于是我又定义了一个NameValueCollection类型

     public class NameValueCollection : IEnumerable<KeyValuePair<string, StringContainer>>
{
public NameValueCollection()
{
collection = new Dictionary<string, StringContainer>(StringComparer.Ordinal);
}
private IDictionary<string, StringContainer> collection = null; public StringContainer this[string key]
{
get {
if (collection.ContainsKey(key))
{
return collection[key];
}
else
{
return StringContainer.Empty;
}
}
set {
if (value.value==null)
{
if (collection.ContainsKey(key))
{
collection.Remove(key);
}
}
else
{
if (collection.ContainsKey(key))
{
collection[key] = value;
}
else
{
collection.Add(key, value);
}
}
}
}
public void Add(string key, string value)
{
this[key]=value;
} public IEnumerator<KeyValuePair<string, StringContainer>> GetEnumerator()
{
return collection.GetEnumerator();
} public override string ToString()
{
StringWriter sw = new StringWriter();
bool firstChild = true;
foreach (var item in collection)
{
if (firstChild)
{
firstChild = false;
}
else
{
sw.Write("&");
}
sw.Write(item.Key);
sw.Write("=");
sw.Write(NFinal.Utility.UrlEncode(item.Value));
}
return sw.ToString();
} IEnumerator IEnumerable.GetEnumerator()
{
return collection.GetEnumerator();
}
}

这样的话,Form类型是否可以这样写?

int a=context.request.Form["a"];
byte? b=context.request.Form["b"];
float c=context.request.Form["c"];
DateTime d=context.request.Form["d"];

一个函数的参数类型与参数类型均不确定的函数如何定义?是不是想不到,那我们看看以下函数。

 //函数
public void Run(params StringContainer[] scArray)
{
  
}

我们在调用时,仅仅需要instance.Run(1,"3",4.5,DateTime.Now);

当然也可以这样写:

 public void Run(NameValueCollection nvc)
{ }

调用时:

 NameValueCollection nvc=new NameValueCollection();
nvc.Add("a",);
nvc.Add("b",1.5);
nvc.Add("c",DateTime.Now);
instance.Run(nvc);

当然更进一步的话,我们可以利用.net 4.0的dynamic特性实现以下效果:

int a=context.request.Form.a;
byte? b=context.request.Form.b;
float c=context.request.Form.c;
DateTime d=context.request.Form.d;

具体思路就不在这里讲了。直接贴代码。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic; namespace NFinal.Collections
{
public class NameValueDynamicCollection: DynamicObject, IDictionary<string, StringContainer>
{
private readonly IDictionary<string, StringContainer> _obj;
public NameValueDynamicCollection()
{
_obj = new Dictionary<string, StringContainer>();
}
public NameValueDynamicCollection(IDictionary<string, StringContainer> obj)
{
_obj = obj;
} public StringContainer this[string key]
{
get
{
StringContainer result;
if (_obj.TryGetValue(key, out result))
{
return result;
}
else
{
return StringContainer.Empty;
}
}
set
{
if (_obj.ContainsKey(key))
{
_obj[key] = value;
}
else
{
_obj.Add(key, value);
}
}
} [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "", Justification = "The compiler generates calls to invoke this")]
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this[binder.Name];
return true;
} [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "", Justification = "The compiler generates calls to invoke this")]
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (value == null)
{
this[binder.Name] = StringContainer.Empty;
}
else
{
this[binder.Name] =new StringContainer(value.ToString());
}
return true;
} public void Add(string key, StringContainer value)
{
if (!_obj.ContainsKey(key))
{
_obj.Add(key, value);
}
} public bool ContainsKey(string key)
{
return _obj.ContainsKey(key);
} public ICollection<string> Keys
{
get { return _obj.Keys; }
} public bool Remove(string key)
{
return _obj.Remove(key);
} public bool TryGetValue(string key, out StringContainer value)
{
return _obj.TryGetValue(key, out value);
} public ICollection<StringContainer> Values
{
get { return _obj.Values; }
} public void Add(KeyValuePair<string, StringContainer> item)
{
_obj.Add(item);
} public void Clear()
{
_obj.Clear();
} public bool Contains(KeyValuePair<string, StringContainer> item)
{
return _obj.Contains(item);
} public void CopyTo(KeyValuePair<string, StringContainer>[] array, int arrayIndex)
{
_obj.CopyTo(array, arrayIndex);
} public int Count
{
get { return _obj.Count; }
} public bool IsReadOnly
{
get { return _obj.IsReadOnly; }
} public bool Remove(KeyValuePair<string, StringContainer> item)
{
return _obj.Remove(item);
} public IEnumerator<KeyValuePair<string, StringContainer>> GetEnumerator()
{
return _obj.GetEnumerator();
} IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

具体代码实现,请参看https://git.oschina.net/LucasDot/NFinal2