3

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

  1. 对于原始类型,我使用 Convert.ChangeType() 方法
  2. 对于枚举类型 - Enum.TryParse()
  3. 对于所有其他自定义类型,我创建了一个接口“IConvertibleFromString”,其中包含一个方法“FromString()”以将字符串转换为指定的类型。任何需要从字符串转换的类都必须实现这个接口。

但我不喜欢我实现方法 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);
    }
}
4

3 回答 3

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;

    }
于 2013-05-20T17:04:23.290 回答
1

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

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

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

于 2013-05-20T17:09:43.693 回答
0

当前的事物结构不允许它成为真正的 StringToType ,因为您无法在拥有“已激活”实例之前调用 FromString 。当您的 FromString 被调用时,另一个实例被创建并返回 - 这意味着您每次都需要创建 2 个实例来实现您想要的。

如果您希望它完美运行,这是我的建议:

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

  2. 创建一个类型的方法 - StringActivator.CreateInstance(string...)

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

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

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

为此,如果 T 是 Primitive 或 ENum(递归的停止条件),您需要检查 CreateInstance 的开头,然后使用 (T)Convert 。

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

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

希望能帮助到你。

于 2013-05-20T17:16:39.123 回答