我试图创建一个通用扩展,使用'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;
}
}
我设法弄到了这样的东西
var result = "44".TryParse<int>();
Console.WriteLine( "type={0}, value={1}, valid={2}",
result.Value.GetType(), result.Value, result.IsValid );
这是我的代码
public static class TryParseGeneric
{
//extend int
public static dynamic TryParse<T>( this string input )
{
dynamic runner = new StaticMembersDynamicWrapper( typeof( T ) );
T value;
bool isValid = runner.TryParse( input, out value );
return new { IsValid = isValid, Value = value };
}
}
public class StaticMembersDynamicWrapper : DynamicObject
{
private readonly Type _type;
public StaticMembersDynamicWrapper( Type type ) { _type = type; }
// Handle static properties
public override bool TryGetMember( GetMemberBinder binder, out object result )
{
PropertyInfo prop = _type.GetProperty( binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public );
if ( prop == null )
{
result = null;
return false;
}
result = prop.GetValue( null, null );
return true;
}
// 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 = null;
return false;
}
result = method.Invoke( null, args );
return true;
}
}
StaticMembersDynamicWrapper改编自David Ebbo的文章(它抛出了一个ambiguous uousmatchexception)
这为每个泛型类型使用一个静态构造函数,因此它只需要在您第一次对给定类型调用它时执行昂贵的工作。它处理系统名称空间中具有TryParse方法的所有类型。它也适用于这些(结构体)的可空版本,但枚举除外。
public static bool TryParse<t>(this string Value, out t result)
{
return TryParser<t>.TryParse(Value.SafeTrim(), out result);
}
private delegate bool TryParseDelegate<t>(string value, out t result);
private static class TryParser<T>
{
private static TryParseDelegate<T> parser;
// Static constructor:
static TryParser()
{
Type t = typeof(T);
if (t.IsEnum)
AssignClass<T>(GetEnumTryParse<T>());
else if (t == typeof(bool) || t == typeof(bool?))
AssignStruct<bool>(bool.TryParse);
else if (t == typeof(byte) || t == typeof(byte?))
AssignStruct<byte>(byte.TryParse);
else if (t == typeof(short) || t == typeof(short?))
AssignStruct<short>(short.TryParse);
else if (t == typeof(char) || t == typeof(char?))
AssignStruct<char>(char.TryParse);
else if (t == typeof(int) || t == typeof(int?))
AssignStruct<int>(int.TryParse);
else if (t == typeof(long) || t == typeof(long?))
AssignStruct<long>(long.TryParse);
else if (t == typeof(sbyte) || t == typeof(sbyte?))
AssignStruct<sbyte>(sbyte.TryParse);
else if (t == typeof(ushort) || t == typeof(ushort?))
AssignStruct<ushort>(ushort.TryParse);
else if (t == typeof(uint) || t == typeof(uint?))
AssignStruct<uint>(uint.TryParse);
else if (t == typeof(ulong) || t == typeof(ulong?))
AssignStruct<ulong>(ulong.TryParse);
else if (t == typeof(decimal) || t == typeof(decimal?))
AssignStruct<decimal>(decimal.TryParse);
else if (t == typeof(float) || t == typeof(float?))
AssignStruct<float>(float.TryParse);
else if (t == typeof(double) || t == typeof(double?))
AssignStruct<double>(double.TryParse);
else if (t == typeof(DateTime) || t == typeof(DateTime?))
AssignStruct<DateTime>(DateTime.TryParse);
else if (t == typeof(TimeSpan) || t == typeof(TimeSpan?))
AssignStruct<TimeSpan>(TimeSpan.TryParse);
else if (t == typeof(Guid) || t == typeof(Guid?))
AssignStruct<Guid>(Guid.TryParse);
else if (t == typeof(Version))
AssignClass<Version>(Version.TryParse);
}
private static void AssignStruct<t>(TryParseDelegate<t> del)
where t: struct
{
TryParser<t>.parser = del;
if (typeof(t).IsGenericType
&& typeof(t).GetGenericTypeDefinition() == typeof(Nullable<>))
{
return;
}
AssignClass<t?>(TryParseNullable<t>);
}
private static void AssignClass<t>(TryParseDelegate<t> del)
{
TryParser<t>.parser = del;
}
public static bool TryParse(string Value, out T Result)
{
if (parser == null)
{
Result = default(T);
return false;
}
return parser(Value, out Result);
}
}
private static bool TryParseEnum<t>(this string Value, out t result)
{
try
{
object temp = Enum.Parse(typeof(t), Value, true);
if (temp is t)
{
result = (t)temp;
return true;
}
}
catch
{
}
result = default(t);
return false;
}
private static MethodInfo EnumTryParseMethod;
private static TryParseDelegate<t> GetEnumTryParse<t>()
{
Type type = typeof(t);
if (EnumTryParseMethod == null)
{
var methods = typeof(Enum).GetMethods(
BindingFlags.Public | BindingFlags.Static);
foreach (var method in methods)
if (method.Name == "TryParse"
&& method.IsGenericMethodDefinition
&& method.GetParameters().Length == 2
&& method.GetParameters()[0].ParameterType == typeof(string))
{
EnumTryParseMethod = method;
break;
}
}
var result = Delegate.CreateDelegate(
typeof(TryParseDelegate<t>),
EnumTryParseMethod.MakeGenericMethod(type), false)
as TryParseDelegate<t>;
if (result == null)
return TryParseEnum<t>;
else
return result;
}
private static bool TryParseNullable<t>(string Value, out t? Result)
where t: struct
{
t temp;
if (TryParser<t>.TryParse(Value, out temp))
{
Result = temp;
return true;
}
else
{
Result = null;
return false;
}
}
如果你设置使用TryParse,你可以使用反射并像这样做:
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});
}
我设法弄到了这样的东西
var result = "44".TryParse<int>();
Console.WriteLine( "type={0}, value={1}, valid={2}",
result.Value.GetType(), result.Value, result.IsValid );
这是我的代码
public static class TryParseGeneric
{
//extend int
public static dynamic TryParse<T>( this string input )
{
dynamic runner = new StaticMembersDynamicWrapper( typeof( T ) );
T value;
bool isValid = runner.TryParse( input, out value );
return new { IsValid = isValid, Value = value };
}
}
public class StaticMembersDynamicWrapper : DynamicObject
{
private readonly Type _type;
public StaticMembersDynamicWrapper( Type type ) { _type = type; }
// Handle static properties
public override bool TryGetMember( GetMemberBinder binder, out object result )
{
PropertyInfo prop = _type.GetProperty( binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public );
if ( prop == null )
{
result = null;
return false;
}
result = prop.GetValue( null, null );
return true;
}
// 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 = null;
return false;
}
result = method.Invoke( null, args );
return true;
}
}
StaticMembersDynamicWrapper改编自David Ebbo的文章(它抛出了一个ambiguous uousmatchexception)
这是另一个选择。
我编写了一个类,可以轻松注册任意数量的TryParse处理程序。它让我这样做:
var tp = new TryParser();
tp.Register<int>(int.TryParse);
tp.Register<decimal>(decimal.TryParse);
tp.Register<double>(double.TryParse);
int x;
if (tp.TryParse("42", out x))
{
Console.WriteLine(x);
};
我将42打印到控制台。
这个类是:
public class TryParser
{
public delegate bool TryParseDelegate<T>(string s, out T result);
private Dictionary<Type, Delegate> _tryParsers = new Dictionary<Type, Delegate>();
public void Register<T>(TryParseDelegate<T> d)
{
_tryParsers[typeof(T)] = d;
}
public bool Deregister<T>()
{
return _tryParsers.Remove(typeof(T));
}
public bool TryParse<T>(string s, out T result)
{
if (!_tryParsers.ContainsKey(typeof(T)))
{
throw new ArgumentException("Does not contain parser for " + typeof(T).FullName + ".");
}
var d = (TryParseDelegate<T>)_tryParsers[typeof(T)];
return d(s, out result);
}
}