很抱歉,我不得不重新编辑这个问题。
我需要动态地将两个字符串值解析为适当的类型并进行比较,然后返回一个bool结果。
示例1:
string lhs = “10”;
string rhs = “10”;
Compare.DoesEqual(lhs, rhs, typeof(int)); //true
Compare.DoesEqual(lhs, rhs, typeof(string)); //true
示例2:
string lhs = “2.0”;
string rhs = “3.1”;
Compare.IsGreaterThan(lhs, rhs, typeof(int)); //false
Compare.IsGreaterThan(lhs, rhs, typeof(double)); //false
Compare.IsGreaterThan(lhs, rhs, typeof(string)); //invalid, always false
目前我这样做(我认为这样做是愚蠢的):
public partial class Comparer
{
public static bool DoesEqual(string lhs, string rhs, Type type)
{
if (type.Equals(typeof(int)))
{
try
{
return int.Parse(lhs) > int.Parse(rhs);
}
catch
{
return false;
}
}
if (type.Equals(typeof(double)))
{
try
{
return double.Parse(lhs) > double.Parse(rhs);
}
catch
{
return false;
}
}
return false;
}
}
而且:
public partial class Comparer
{
public static bool IsGreaterThan(string lhs, string rhs, Type type)
{
if (type.Equals(typeof(int)))
{
try
{
return int.Parse(lhs) == int.Parse(rhs);
}
catch
{
return false;
}
}
if (type.Equals(typeof(double)))
{
try
{
return double.Parse(lhs) == double.Parse(rhs);
}
catch
{
return false;
}
}
if (type.Equals(typeof(string)))
{
return lhs.Equals(rhs);
}
return false;
}
}
我正在寻找更好的(更通用的方式)实现(也许使用表达式树?)。我很感激任何建议。谢谢!
答案 0 :(得分:3)
最通用的方法是使用TypeConverter
。假设我们有:
string rhs = ...;
string lhs = ...;
Type type = ...;
来自某个地方。你可以这样做:
TypeConverter conv = TypeDescriptor.GetConverter(type);
try
{
object rho = conv.ConvertFrom(rhs);
object lho = conv.ConvertFrom(lhs);
...
}
catch (NotSupportedException)
{
// No luck - couldn't parse the string
}
不幸的是,在处理转换器时,没有办法避免catch
。现在您有两个从字符串解析的对象,您可以进行泛型比较。平等很简单 - 只需使用Object.Equals
(最好是静态的 - 它处理空值):
if (Object.Equals(rho, lho))
{
...
}
对于订购比较,您可以检查类型是否支持IComparable
:
IComparable rhc = rho as IComparable;
if (rhc != null && rhc.CompareTo(lho) < 0) // rhs less than lhs
{
...
}
但是请注意,某些未提供operator<
的类型仍然是有序的,因此实施IComparable
- 例如,String
会这样做。
答案 1 :(得分:1)
哦,我很想拥有这个问题。 :)
编辑:测试:
[TestMethod]
public void TestDynamicComparer()
{
string lhs = "10";
string rhs = "10";
Assert.AreEqual(0, DynamicComparer<int>.Default.Compare(lhs, rhs));
lhs = "2.0";
rhs = "3.1";
// basic equality
Assert.AreNotEqual(0, DynamicComparer<double>.Default.Compare(lhs, rhs));
// correct order
Assert.IsTrue(DynamicComparer<double>.Default.Compare(lhs, rhs) < 0);
// check two invalid casts are unordered
Assert.AreEqual(0, DynamicComparer<int>.DefaultNoThrow.Compare(lhs, rhs));
// real proof it works
lhs = "9";
rhs = "09";
Assert.AreEqual(0, DynamicComparer<int>.Default.Compare(lhs, rhs));
lhs = "9.0";
rhs = "09";
Assert.AreEqual(0, DynamicComparer<double>.Default.Compare(lhs, rhs));
// test the valid cast is ordered ahead of ("less than") the invalid cast
Assert.AreNotEqual(0, DynamicComparer<int>.DefaultNoThrow.Compare(lhs, rhs));
Assert.IsTrue(DynamicComparer<int>.DefaultNoThrow.Compare(lhs, rhs) > 0);
}
[TestMethod]
[ExpectedException(typeof(InvalidCastException))]
public void TestDynamicComparerInvalidCast()
{
// make sure the default comparer throws an InvalidCastException if a cast fails
string lhs = "2.0";
string rhs = "3.1";
DynamicComparer<int>.Default.Compare(lhs, rhs);
}
胆量:
public class DynamicComparer<T>
: IComparer<string>
, IEqualityComparer<string>
{
private static readonly DynamicComparer<T> defaultComparer = new DynamicComparer<T>();
private static readonly DynamicComparer<T> defaultNoThrowComparer = new DynamicComparer<T>(false);
private DynamicComparerHelper.TryParseDelegate<T> parser = DynamicComparerHelper.GetParser<T>();
private IComparer<T> comparer;
private bool throwOnError;
public DynamicComparer()
: this(Comparer<T>.Default, true)
{
}
public DynamicComparer(bool throwOnError)
: this(Comparer<T>.Default, throwOnError)
{
}
public DynamicComparer(IComparer<T> comparer)
: this(comparer, true)
{
}
public DynamicComparer(IComparer<T> comparer, bool throwOnError)
{
this.comparer = comparer;
this.throwOnError = throwOnError;
}
public static DynamicComparer<T> Default
{
get
{
return defaultComparer;
}
}
public static DynamicComparer<T> DefaultNoThrow
{
get
{
return defaultNoThrowComparer;
}
}
public int Compare(string x, string y)
{
T valueX;
T valueY;
bool convertedX = this.parser(x, out valueX);
bool convertedY = this.parser(y, out valueY);
if (this.throwOnError && !(convertedX && convertedY))
throw new InvalidCastException();
if (!(convertedX || convertedY))
return 0;
if (!convertedX)
return 1;
if (!convertedY)
return -1;
return this.comparer.Compare(valueX, valueY);
}
public bool Equals(string x, string y)
{
return Compare(x, y) == 0;
}
public int GetHashCode(string x)
{
T value;
bool converted = this.parser(x, out value);
if (this.throwOnError && !converted)
throw new InvalidCastException();
if (!converted)
return 0;
return value.GetHashCode();
}
}
internal class DynamicComparerHelper
{
public delegate bool TryParseDelegate<T>(string text, out T value);
private static readonly Dictionary<Type, Delegate> converters =
new Dictionary<Type, Delegate>()
{
{ typeof(bool), WrapDelegate<bool>(bool.TryParse) },
{ typeof(short), WrapDelegate<short>(short.TryParse) },
{ typeof(int), WrapDelegate<int>(int.TryParse) },
{ typeof(long), WrapDelegate<long>(long.TryParse) },
{ typeof(ushort), WrapDelegate<ushort>(ushort.TryParse) },
{ typeof(uint), WrapDelegate<uint>(uint.TryParse) },
{ typeof(ulong), WrapDelegate<ulong>(ulong.TryParse) },
{ typeof(float), WrapDelegate<float>(float.TryParse) },
{ typeof(double), WrapDelegate<double>(double.TryParse) },
{ typeof(DateTime), WrapDelegate<DateTime>(DateTime.TryParse) },
};
public static TryParseDelegate<T> GetParser<T>()
{
return (TryParseDelegate<T>)converters[typeof(T)];
}
private static TryParseDelegate<T> WrapDelegate<T>(TryParseDelegate<T> parser)
{
return new TryParseDelegate<T>(parser);
}
}
答案 2 :(得分:-2)
这是家庭作业吗?
我的意思是,答案是编写类/方法的实现。
您遇到的具体问题是什么?究竟是什么让你不明白?
如果你将问题分解成部分就变得容易了。