Generic TryParse

2019-01-02 19:47发布

I am trying to create a generic extension that uses 'TryParse' to check if a string is a given type:

public static bool Is<T>(this string input)
{
    T notUsed;
    return T.TryParse(input, out notUsed);
}

this won't compile as it cannot resolve symbol 'TryParse'

As I understand, 'TryParse' is not part of any interface.

Is this possible to do at all?

Update:

Using the answers below I have come up with:

public static bool Is<T>(this string input)
{
    try
    {
        TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(input);
    }
    catch
    {
        return false;
    }

    return true;
}

It works quite well but I think using exceptions in that way doesn't feel right to me.

Update2:

Modified to pass type rather than use generics:

public static bool Is(this string input, Type targetType)
{
    try
    {
        TypeDescriptor.GetConverter(targetType).ConvertFromString(input);
        return true;
    }
    catch
    {
        return false;
    }
}

18条回答
若你有天会懂
2楼-- · 2019-01-02 20:38

When I wanted to do almost this exact thing, I had to implement it the hard way, given reflection. Given T, reflect on typeof(T) and look for a TryParse or Parse method, invoking it if you've found it.

查看更多
流年柔荑漫光年
3楼-- · 2019-01-02 20:38

A version for getting descendants from XDocument.

public static T Get<T>(XDocument xml, string descendant, T @default)
{
    try
    {
        var converter = TypeDescriptor.GetConverter(typeof (T));
        if (converter != null)
        {
            return (T) converter.ConvertFromString(xml.Descendants(descendant).Single().Value);
        }
        return @default;
    }
    catch
    {
        return @default;
    }
}
查看更多
荒废的爱情
4楼-- · 2019-01-02 20:42

This is a question of 'generic constraints'. Because you don't have a specific interface then you are stuck unless you follow the suggestions of the previous answer.

For documentation on this, check the following link:

http://msdn.microsoft.com/en-us/library/ms379564(VS.80).aspx

It shows you how to use these constraints and should give you some more clues.

查看更多
余生无你
5楼-- · 2019-01-02 20:43

If you are set on using TryParse, you can use reflection and do it like this:

public static bool Is<T>(this string input)
{
    var type = typeof (T);
    var temp = default(T);
    var method = type.GetMethod(
        "TryParse",
        new[]
            {
                typeof (string),
                Type.GetType(string.Format("{0}&", type.FullName))
            });
    return (bool) method.Invoke(null, new object[] {input, temp});
}
查看更多
只靠听说
6楼-- · 2019-01-02 20:44
public static T Get<T>(string val)
{ 
    return (T) TypeDescriptor.GetConverter(typeof (T)).ConvertFromInvariantString(val);
}
查看更多
骚的不知所云
7楼-- · 2019-01-02 20:45

Quite a bit late to the party, but here's what I came up with. No exceptions, one-time (per type) reflection.

public static class Extensions {
    public static T? ParseAs<T>(this string str) where T : struct {
        T val;
        return GenericHelper<T>.TryParse(str, out val) ? val : default(T?);
    }
    public static T ParseAs<T>(this string str, T defaultVal) {
        T val;
        return GenericHelper<T>.TryParse(str, out val) ? val : defaultVal;
    }

    private static class GenericHelper<T> {
        public delegate bool TryParseFunc(string str, out T result);

        private static TryParseFunc tryParse;
        public static TryParseFunc TryParse {
            get {
                if (tryParse == null)
                    tryParse = Delegate.CreateDelegate(
                        typeof(TryParseFunc), typeof(T), "TryParse") as TryParseFunc;
                return tryParse;
            }
        }
    }
}

The extra class is required because extention methods are not permitted inside generic classes. This allows simple usage, as shown below, and only hits reflection the first time a type is used.

"5643".ParseAs<int>()
查看更多
登录 后发表回答