如何从类型到TryParse方法?

时间:2009-01-24 20:11:12

标签: c# parsing types

我的特殊问题:

我有一个字符串,它在配置类中指定了一个任意类型

Config.numberType = "System.Foo";

其中Foo类型为DecimalDouble

我使用Type.GetType(Config.numberType)返回相应的类型。

如何从该类型转变为能够使用System.Foo.TryParse()

一些进一步的相关查询

    可以从TryParse()以及System.Foo.TryParse()访问
  • foo.TryParse()。这是否意味着foo是C#中的某种类?对我来说,intdouble等实际上不仅仅是修饰符关键字,这似乎很奇怪。
  • 如何在这些情况下声明变量? - var似乎并非普遍可用,即仅在本地范围内等。

5 个答案:

答案 0 :(得分:20)

正如许多人所说 - 没有直接路线。我希望有一个关闭选项是TypeConverter

    Type type = typeof(double);
    string text = "123.45";

    object value = TypeDescriptor.GetConverter(type)
        .ConvertFromInvariantString(text);

当然,您可能需要try / catch来处理异常。这就是生活。

答案 1 :(得分:7)

  

我如何从这种类型变为现实   能够使用,System.Foo.TryParse()?

您需要使用反射来查找,然后调用静态TryParse()方法。并非所有类型都实现此方法 - 因此,如果缺少该方法,则必须决定如何处理它。您还可以使用System.Convert将字符串转换为任意类型,假设字符串实际上是该类型的值的有效表示,则为其实现了转换。

  

可以从中访问TryParse()   System.Foo.TryParse()以及   foo.TryParse()。这是否意味着foo   C#中的某种类?

对于intdouble等,

System.Int32System.Double等等aliases - 它们是C#语言的一部分,没有它们会让人感到不舒服。

  

如何在变量下声明变量   这些情况?

在编译时不知道类型,您将被迫声明并使用object / System.Object来处理您的数据。 C#4.0将介绍实际的动态类型,它将为您处理一些繁琐的反射工作,但是现在您已经被卡住了。请注意,如果您use System.Convert方法中的with a parametrized type argument and return或使用linked to by Sebastian Sedlak等技术的TryParse(),您可以轻松实现编写适用于静态的客户端代码的功能types ...只要它们匹配或可以从您正在解析的类型转换为。

答案 2 :(得分:5)

已编辑:我删除了通用实现并清除了此响应以更好地适应最初声明的问题。

注意:如果您只想要给出类型的解析值,Marc Gravell的答案可能是最简洁的。下面的答案向您展示了如何获取方法(即MethodInfo对象以及如何调用它)。

以下应该有效,至少对于实现公共静态bool TryParse(字符串,T值)的类型:

public static class Parsing
{
    static MethodInfo findTryParseMethod(Type type)
    {
        //find member of type with signature 'static public bool TryParse(string, out T)'
        BindingFlags access = BindingFlags.Static | BindingFlags.Public;
        MemberInfo[] candidates = type.FindMembers(
            MemberTypes.Method,
            access,
            delegate(MemberInfo m, object o_ignored)
            {
                MethodInfo method = (MethodInfo)m;
                if (method.Name != "TryParse") return false;
                if (method.ReturnParameter.ParameterType != typeof(bool)) return false;
                ParameterInfo[] parms = method.GetParameters();
                if (parms.Length != 2) return false;
                if (parms[0].ParameterType != typeof(string)) return false;
                if (parms[1].ParameterType != type.MakeByRefType()) return false;
                if (!parms[1].IsOut) return false;

                return true;

            }, null);

        if (candidates.Length > 1)
        {
            //change this to your favorite exception or use an assertion
            throw new System.Exception(String.Format(
                "Found more than one method with signature 'public static bool TryParse(string, out {0})' in type {0}.",
                type));
        }
        if (candidates.Length == 0)
        {
            //This type does not contain a TryParse method - replace this by your error handling of choice
            throw new System.Exception(String.Format(
                "Found no method with signature 'public static bool TryParse(string, out {0})' in type {0}.",
                type));
        }
        return (MethodInfo)candidates[0];
    }

    public static bool TryParse(Type t, string s, out object val)
    {
        MethodInfo method = findTryParseMethod(t); //can also cache 'method' in a Dictionary<Type, MethodInfo> if desired
        object[] oArgs = new object[] { s, null };
        bool bRes = (bool)method.Invoke(null, oArgs);
        val = oArgs[1];
        return bRes;
    }

    //if you want to use TryParse in a generic syntax:
    public static bool TryParseGeneric<T>(string s, out T val)
    {
        object oVal;
        bool bRes = TryParse(typeof(T), s, out oVal);
        val = (T)oVal;
        return bRes;
    }
}

使用以下测试代码:

        public bool test()
    {
        try
        {
            object oVal;
            bool b = Parsing.TryParse(typeof(int), "123", out oVal);
            if (!b) return false;
            int x = (int)oVal;
            if (x!= 123) return false;
        }
        catch (System.Exception)
        {
            return false;
        }

        try
        {
            int x;
            bool b = Parsing.TryParseGeneric<int>("123", out x);
            if (!b) return false;
            if (x != 123) return false;
        }
        catch (System.Exception)
        {
            return false;
        }


        try
        {
            object oVal;
            bool b = Parsing.TryParse(typeof(string), "123", out oVal);
            //should throw an exception (//no method String.TryParse(string s, out string val)
            return false;
        }
        catch (System.Exception)
        {
            //should throw an exception
        }

        return true;
    }
}

在你的情况下使用它:

    //input: string s, Config
Type tNum = Type.GetType(Config.numberType);    
object oVal;
bool ok = Parsing.TryParse(tNum, s, out oVal);
//oVal is now of type tNum and its value is properly defined if ok == true

关于var的使用:你可能对var的作用有误解:它不是一个“variant”类型(类型对象已经用于此类型),但是将类型的声明语法移动到赋值的右侧。以下声明是等效的:

var i = 1;  //the compiler infers the type from the assignment, type of i is int.
int i = 1;  //type of i is int via declaration

var的主要用途是允许创建匿名类型

var anon = new { Name = "abc", X = 123 };

答案 3 :(得分:2)

另一个good link to this problem。该网站上的源代码格式非常糟糕,所以我把它放在这里。希望作者不要起诉我。

public static T Parse<T>(string s)
{
    Type t = typeof(T);
    // Attempt to execute the Parse method on the type if it exists. 
    MethodInfo parse = t.GetMethod("Parse", new Type[] { typeof(string) });

    if (parse != null)
    {
        try
        {
            return (T)parse.Invoke(null, new object[] { s });
        }
        catch (Exception ex)
        {
            throw ex.InnerException;
        }
    }
    else
    {
        throw new MethodAccessException(String.Format("The Parse method does not exist for type {0}.", t.Name));
    }
}

public static bool TryParse<T>(string s, out T result)
{
    return TryParse<T>(s, false, out result);
}

public static bool TryParse<T>(string s, bool throwException, out T result)
{
    result = default(T);
    Type t = typeof(T);
    T type = default(T);

    // Look for the TryParse method on the type. 
    MethodInfo tryParse = t.GetMethod("TryParse", new Type[] { typeof(string), Type.GetType(t.FullName + "&") });
    if (tryParse != null)
    {
        // Try parse exists. Call it. 
        Object[] ps = new Object[2];
        ps[0] = s;

        bool isSuccess = (bool)tryParse.Invoke(type, ps);

        if (isSuccess)
            result = (T)ps[1];

        return isSuccess;
    }
    else
    {
        // TryParse does not exist. Look for a Parse method. 
        try
        {
            result = Parse<T>(s);
            return true;
        }
        catch
        {
            if (throwException)
                throw;

            return false;
        }
    }
}

答案 4 :(得分:1)