字符串的通用泛型类型转换

时间:2013-05-20 16:08:45

标签: c# generics type-conversion

我的任务是编写一个方法StringToType(),将字符串转换为指定的类型T.

  1. 对于基本类型,我使用方法Convert.ChangeType()
  2. 对于枚举类型 - Enum.TryParse()
  3. 对于所有其他自定义类型,我创建了一个接口“IConvertibleFromString”,其中包含一个方法“FromString()”,将字符串转换为指定的类型。任何需要从字符串转换的类都必须实现此接口。
  4. 但我不喜欢我实现方法StringToType()的方式。我想使用少于反射并尽可能确保性能。

    请告知如何最好地实施/更改它。

    class Program
    {
        static bool StringToType<T>(string str, ref T value)
        {
            Type typeT = typeof(T);
            bool isSuccess = false;
            if (typeT.GetInterface("IConvertibleFromString") != null)
            {
                return (bool)typeT.GetMethod("FromString").Invoke(value, new object[] { str });
            }
            else if (typeT.IsEnum)
            {
                MethodInfo methodTryParse = typeT.GetMethod("TryParse").MakeGenericMethod(typeT);
                return (bool)methodTryParse.Invoke(null, new object[] { str, value });
            }
            else if (typeT.IsPrimitive)
            {
                value = (T)Convert.ChangeType(str, typeT);
                return true;
            }
            return isSuccess;
        }
    
        static void Main(string[] args)
        {
            string intStr = "23";
            int val1 = 0;
            bool res = StringToType<int>(intStr, ref val1);
            Class1 c1;
            res = StringToType<Class1>(intStr, ref c1);
            Console.ReadKey();
        }
    }
    
    interface IConvertibleFromString
    {
        bool FromString(string str);
    }
    
    class MySomeClass : IConvertibleFromString
    {
        int someVal;
    
        public bool FromString(string str)
        {
            return int.TryParse(str, out someVal);
        }
    }
    

3 个答案:

答案 0 :(得分:5)

这似乎对我来说是最好的。与各种消费者共同投入了一百万次。这是人们评论的结合,还有一些额外的。

    static Boolean TryParseString<T>(
        String stringValue, ref T value)
    {

        Type typeT = typeof(T);

        if (typeT.IsPrimitive)
        {
            value = (T)Convert.ChangeType(stringValue, typeT);
            return true;
        }
        else if (typeT.IsEnum)
        {
            value = (T)System.Enum.Parse(typeT, stringValue); // Yeah, we're making an assumption
            return true;
        }
        else
        {
            var convertible = value as IConvertible;
            if (convertible != null)
            {
                return convertible.FromString(stringValue);
            }
        }

        return false;

    }

答案 1 :(得分:1)

对于案例#1,它已经是最佳的。

对于案例#2,您可以使用Enum.Parse并捕获ArgumentException并返回false。

对于情况#3,方法FromString是一个静态工厂方法,因此不包含在接口IConvertibleFromString中(因此接口只是一个类型标记而不包含任何方法)或者它是一个变异this._value或其他东西的实例方法,目前尚不清楚。如果是后者,那么只需将value投射到IConvertibleFromString并调用FromString,就不需要反思。如果它是静态工厂方法,那么你必须使用反射。

答案 2 :(得分:0)

事物的当前结构不允许它是真正的StringToType,因为你不能调用FromString,因为你有一个“已经活动”的实例。调用FromString时,会创建并返回另一个实例 - 这意味着每次需要创建2个实例实例以实现所需的实例。

如果你想让它完美地运作,这是我的建议:

  1. 创建一个新类 - “StringActivator”(受Reflection的Activator启发)

  2. 创建一个Type方法 - StringActivator.CreateInstance(string ...)

  3. 激活字符串是一个由逗号分隔的/ xml字符串组成的字符串,其中每个项目都是构造函数参数。

  4. 在里面,查看类型(T)构造函数,找到具有所需参数数量的所有构造函数(在激活字符串中发送)。

  5. 现在,一旦你拥有了所有构造函数,尝试将你在激活字符串中发送的每个参数值转换为构造函数使用Recursion所期望的类型(调用StringActivator.CreateInstane,其中T是构造函数所期望的类型)

  6. 要使其工作,如果T是Primitive或ENum(Recursion的停止条件),则需要检查CreateInstance的开头,然后使用(T)转换。

    1. 当您转换所有逗号分隔的参数时,请使用Reflection.Emit为您发送的特定数量的参数创建编译调用。

    2. 将发出的函数委托映射到Type sent(),并在下次尝试从具有相同参数数量的字符串转换为T时调用它...

    3. 希望它有所帮助。