zoukankan      html  css  js  c++  java
  • 字符串类型的自动转换与识别

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

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

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

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

    1 int temp;
    2 bool success= Int32.TryParse("23",out temp);
    3 if(!success)
    4 {
    5     temp=0;              
    6 }

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

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

     1 //能够存储基本类型
     2 public void Test1()
     3 {
     4     StringContainer a= 1;
     5     StringContainer b="2";
     6     StringContainer c=DateTime.Now;   
     7 }
     8 //能够自动转换类型
     9 public void Test2(StringContainer d)
    10 {
    11     StringContainer a="1";
    12     int b= a + 1; 
    13     DataTime c=a; 
    14     Console.Write(d);
    15 }
    16 //能够调用同一个函数,但参数类型可以不一样
    17 public void Test3()
    18 {
    19     Test2(2);
    20     Test2(1.2f);
    21     Test2(DateTime.Now);  
    22 }

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

     1 public struct StringContainer
     2 {
     3         public static readonly StringContainer Empty=new StringContainer();
     4         public string value;
     5         internal StringContainer(string value)
     6         {
     7             this.value = value;
     8         }
     9         public static implicit operator StringContainer(string value)
    10         {
    11             return new StringContainer(value);
    12         }
    13         public static implicit operator string(StringContainer stringContainar)
    14         {
    15         return stringContainar.value;
    16         }    
    17         public static implicit operator Int32(StringContainer stringContainar)
    18         {
    19             Int32 result;
    20             Int32.TryParse(stringContainar.value, out result);
    21             return result;
    22         }
    23         public static implicit operator StringContainer(Int32 obj)
    24         {
    25             return new StringContainer(obj.ToString());
    26     }
    27 }

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

    1 public static implicit operator StringContainer(string value)
    2 {
    3     return new StringContainer(value);
    4 }

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

    StringContainer str = "23";

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

    1 public static implicit operator Int32(StringContainer stringContainar)
    2 {
    3     Int32 result;
    4     Int32.TryParse(stringContainar.value, out result);
    5     return result;
    6 }

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

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

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

    // Method begins at RVA 0x2130
        // Code size 20 (0x14)
        .maxstack 1
        .locals init (
            [0] valuetype [NFinal4]System.StringContainer str,
            [1] 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=0;i<structType.Length;i++){#>
            public static implicit operator StringContainer(<#=structType[i]#> obj)
            {
                return new StringContainer(obj.ToString());
            }
    <#    }#>
    <#    for(int i=0;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=0;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=0;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;
                }
            }
    <#}#>
        }
    }

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

    1 StringContainer str="23";
    2 int b=str*4;
    3 str=DateTime.Now;
    4 str.ToString();
    5 str=4.33;
    6 double? a=str+1;

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

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

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

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

     1     public class NameValueCollection : IEnumerable<KeyValuePair<string, StringContainer>>
     2     {
     3         public NameValueCollection()
     4         {
     5             collection = new Dictionary<string, StringContainer>(StringComparer.Ordinal);
     6         }
     7         private IDictionary<string, StringContainer> collection = null;
     8 
     9         public StringContainer this[string key]
    10         {
    11             get {
    12                 if (collection.ContainsKey(key))
    13                 {
    14                     return collection[key];
    15                 }
    16                 else
    17                 {
    18                     return StringContainer.Empty;
    19                 }
    20             }
    21             set {
    22                 if (value.value==null)
    23                 {
    24                     if (collection.ContainsKey(key))
    25                     {
    26                         collection.Remove(key);
    27                     }
    28                 }
    29                 else
    30                 {
    31                     if (collection.ContainsKey(key))
    32                     {
    33                         collection[key] = value;
    34                     }
    35                     else
    36                     {
    37                         collection.Add(key, value);
    38                     }
    39                 }
    40             }
    41         }
    42         public void Add(string key, string value)
    43         {
    44             this[key]=value;
    45         }
    46 
    47         public IEnumerator<KeyValuePair<string, StringContainer>> GetEnumerator()
    48         {
    49             return collection.GetEnumerator();
    50         }
    51 
    52         public override string ToString()
    53         {
    54             StringWriter sw = new StringWriter();
    55             bool firstChild = true;
    56             foreach (var item in collection)
    57             {
    58                 if (firstChild)
    59                 {
    60                     firstChild = false;
    61                 }
    62                 else
    63                 {
    64                     sw.Write("&");
    65                 }
    66                 sw.Write(item.Key);
    67                 sw.Write("=");
    68                 sw.Write(NFinal.Utility.UrlEncode(item.Value));
    69             }
    70             return sw.ToString();
    71         }
    72 
    73         IEnumerator IEnumerable.GetEnumerator()
    74         {
    75             return collection.GetEnumerator();
    76         }
    77     }

    这样的话,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"];

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

    1 //函数
    2 public void Run(params StringContainer[] scArray)
    3 {
    4       
    5 }

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

    当然也可以这样写:

    1 public void Run(NameValueCollection nvc)
    2 {
    3 
    4 }

    调用时:

    1 NameValueCollection nvc=new NameValueCollection();
    2 nvc.Add("a",1);
    3 nvc.Add("b",1.5);
    4 nvc.Add("c",DateTime.Now);
    5 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 = "0", 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 = "0", 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

    NFinal2开源框架。https://git.oschina.net/LucasDot/NFinal2/tree/master qq:348764327.
  • 相关阅读:
    无锁队列的实现
    C/C++语言中闭包的探究及比较
    Linus:利用二级指针删除单向链表
    Unix考古记:一个“遗失”的shell
    “C++的数组不支持多态”?
    Alan Cox:单向链表中prev指针的妙用
    二叉树迭代器算法
    C语言全局变量那些事儿
    数据即代码:元驱动编程
    C++模板”>>”编译问题与词法消歧设计
  • 原文地址:https://www.cnblogs.com/LucasDot/p/6484109.html
Copyright © 2011-2022 走看看