我试图创建一个通用扩展,使用'TryParse'来检查字符串是否为给定类型:
public static bool Is<T>(this string input)
{
T notUsed;
return T.TryParse(input, out notUsed);
}
这将无法编译,因为它无法解析符号TryParse
据我所知,“TryParse”不是任何接口的一部分。
这有可能吗?
更新:
使用以下我想出的答案:
public static bool Is<T>(this string input)
{
try
{
TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(input);
}
catch
{
return false;
}
return true;
}
它工作得很好,但我认为以这种方式使用异常对我来说不合适。
更新2:
修改为传递类型而不是使用泛型:
public static bool Is(this string input, Type targetType)
{
try
{
TypeDescriptor.GetConverter(targetType).ConvertFromString(input);
return true;
}
catch
{
return false;
}
}
像这样的怎么样?
http://madskristensen.net/post/Universal-data-type-checker.aspx(存档)
/// <summary>
/// Checks the specified value to see if it can be
/// converted into the specified type.
/// <remarks>
/// The method supports all the primitive types of the CLR
/// such as int, boolean, double, guid etc. as well as other
/// simple types like Color and Unit and custom enum types.
/// </remarks>
/// </summary>
/// <param name="value">The value to check.</param>
/// <param name="type">The type that the value will be checked against.</param>
/// <returns>True if the value can convert to the given type, otherwise false. </returns>
public static bool CanConvert(string value, Type type)
{
if (string.IsNullOrEmpty(value) || type == null) return false;
System.ComponentModel.TypeConverter conv = System.ComponentModel.TypeDescriptor.GetConverter(type);
if (conv.CanConvertFrom(typeof(string)))
{
try
{
conv.ConvertFrom(value);
return true;
}
catch
{
}
}
return false;
}
这可以很容易地转换为泛型方法。
public static bool Is<T>(this string value)
{
if (string.IsNullOrEmpty(value)) return false;
var conv = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));
if (conv.CanConvertFrom(typeof(string)))
{
try
{
conv.ConvertFrom(value);
return true;
}
catch
{
}
}
return false;
}
我最近还需要一个通用的TryParse。这是我想到的;
public static T? TryParse<T>(string value, TryParseHandler<T> handler) where T : struct
{
if (String.IsNullOrEmpty(value))
return null;
T result;
if (handler(value, out result))
return result;
Trace.TraceWarning("Invalid value '{0}'", value);
return null;
}
public delegate bool TryParseHandler<T>(string value, out T result);
那么这就是一个简单的调用问题:
var value = TryParse<int>("123", int.TryParse);
var value2 = TryParse<decimal>("123.123", decimal.TryParse);
我把一堆想法放在一起,最终得到了一个非常简短的解决方案。
这是一个字符串的扩展方法
enter code here
我在数值类型上使用与TryParse方法相同的足迹
/// <summary>
/// string.TryParse()
///
/// This generic extension method will take a string
/// make sure it is not null or empty
/// make sure it represents some type of number e.g. "123" not "abc"
/// It then calls the appropriate converter for the type of T
/// </summary>
/// <typeparam name="T">The type of the desired retrunValue e.g. int, float, byte, decimal...</typeparam>
/// <param name="targetText">The text to be converted</param>
/// <param name="returnValue">a populated value of the type T or the default(T) value which is likely to be 0</param>
/// <returns>true if the string was successfully parsed and converted otherwise false</returns>
/// <example>
/// float testValue = 0;
/// if ( "1234".TryParse<float>( out testValue ) )
/// {
/// doSomethingGood();
/// }
/// else
/// {
/// handleTheBadness();
/// }
/// </example>
public static bool TryParse<T>(this string targetText, out T returnValue )
{
bool returnStatus = false;
returnValue = default(T);
//
// make sure the string is not null or empty and likely a number...
// call whatever you like here or just leave it out - I would
// at least make sure the string was not null or empty
//
if ( ValidatedInputAnyWayYouLike(targetText) )
{
//
// try to catch anything that blows up in the conversion process...
//
try
{
var type = typeof(T);
var converter = TypeDescriptor.GetConverter(type);
if (converter != null && converter.IsValid(targetText))
{
returnValue = (T)converter.ConvertFromString(targetText);
returnStatus = true;
}
}
catch
{
// just swallow the exception and return the default values for failure
}
}
return (returnStatus);
}
'''
借用自http://blogs.msdn.com/b/davidebb/archive/2009/10/23/using-c-dynamic-to-call-static-members.aspx
当遵循这个参考:如何调用静态方法在c# 4.0与动态类型?
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Reflection;
namespace Utils
{
public class StaticMembersDynamicWrapper : DynamicObject
{
private Type _type;
public StaticMembersDynamicWrapper(Type type) { _type = type; }
// Handle static methods
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
var methods = _type
.GetMethods(BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public)
.Where(methodInfo => methodInfo.Name == binder.Name);
var method = methods.FirstOrDefault();
if (method != null)
{
result = method.Invoke(null, args);
return true;
}
result = null;
return false;
}
}
public static class StaticMembersDynamicWrapperExtensions
{
static Dictionary<Type, DynamicObject> cache =
new Dictionary<Type, DynamicObject>
{
{typeof(double), new StaticMembersDynamicWrapper(typeof(double))},
{typeof(float), new StaticMembersDynamicWrapper(typeof(float))},
{typeof(uint), new StaticMembersDynamicWrapper(typeof(uint))},
{typeof(int), new StaticMembersDynamicWrapper(typeof(int))},
{typeof(sbyte), new StaticMembersDynamicWrapper(typeof(sbyte))}
};
/// <summary>
/// Allows access to static fields, properties, and methods, resolved at run-time.
/// </summary>
public static dynamic StaticMembers(this Type type)
{
DynamicObject retVal;
if (!cache.TryGetValue(type, out retVal))
return new StaticMembersDynamicWrapper(type);
return retVal;
}
}
}
使用方法如下:
public static T? ParseNumeric<T>(this string str, bool throws = true)
where T : struct
{
var statics = typeof(T).StaticMembers();
if (throws) return statics.Parse(str);
T retval;
if (!statics.TryParse(str, out retval)) return null;
return retval;
}