I was thinking about writing generic functions for basic Math operations such as Min, Max etc. But i i dont know how to compare two generic types :
我在考虑为基本的数学运算编写泛型函数,如Min、Max等。但是我不知道如何比较两种泛型:
public T Max<T>(T v1, T v2) where T: struct
{
return (v1 > v2 ? v1 : v2);
}
How about that?
你觉得怎么样?
Thank you.
谢谢你!
5 个解决方案
#1
22
If you only want to create comparison functions then you could use the default comparer for the type T
. For example:
如果您只想创建比较函数,那么您可以使用默认比较器对类型t进行比较。
public static T Max<T>(T x, T y)
{
return (Comparer<T>.Default.Compare(x, y) > 0) ? x : y;
}
If T
implements IComparable<T>
then that comparer will be used; if T
doesn't implement IComparable<T>
but does implement IComparable
then that comparer will be used; if T
doesn't implement either IComparable<T>
or IComparable
then a runtime exception will be thrown.
如果T实现了icom克莱伯
If you want/need to do more than just compare the items then you could have a look at the generic operators implementation in MiscUtil and the related article.
如果您想/需要做的不仅仅是比较项目,那么您可以查看一下MiscUtil中的泛型操作符实现和相关文章。
#2
22
You probably want to constrain the generic types to implement IComparable
:
您可能想要约束泛型类型来实现icom寓言:
public T Max<T>(T v1, T v2) where T: struct, IComparable<T>
and then use the CompareTo
method:
然后使用CompareTo方法:
{
return (v1.CompareTo(v2) > 0 ? v1 : v2);
}
#3
4
Let me disagree. The @LukeH's implementation is not Generic.
我不同意。@卢克的实现不是通用的。
I will explain why it is not Generic:
我会解释为什么它不是通用的:
Comparer<T>.Default
involves inspecting T at run-time to determine if it implements IComparable<T>
, IComparable
or neither. Although this behavior is not well documented in http://msdn.microsoft.com/en-us/library/azhsac5f.aspx, we can deduct it because Comparer<T>.Default
throws an exception when T does not implement neither. If the inspection was done at compilation-time there would be no need for an exception (runtime), with an compile-time error would suffice.
比较器< T >。默认情况包括在运行时检查T,以确定它是否实现了icom亦步亦趋的
Then, as Comparer<T>.Default
uses Reflection, this means a high cost on Run-Time, then...., It is NOT Generic... Why?
然后,当比较器< T >。默认使用反射,这意味着高成本运行,然后....,它不是通用的……为什么?
Because Generic Programming means: A single algorithm (Generic) can cover many implementations (for many types) maintaining efficiency of hand-written versions.
因为泛型编程意味着:单个算法(泛型)可以覆盖许多实现(对于许多类型),从而保持手写版本的效率。
Take an example. The handwritten version for integers would be:
举一个例子。手写的整数版本是:
public static int Max( int x, int y)
{
return (x.CompareTo(y) > 0) ? x : y;
}
It is very simple, involving only a comparison (or maybe more, depending on how Int32.CompareTo() is implemented). If we use the @LukeH's implementation, we are adding Reflection to something that is very simple.
它非常简单,只涉及比较(或者更多,取决于Int32.CompareTo()的实现方式)。如果我们使用@卢克的实现,我们就为非常简单的东西添加了反射。
In short:
简而言之:
- Always prefer Compilation-time errors to Run-Time Exceptions ( this is not Javascript, Ruby,... :-) )
- 总是喜欢编译时错误而不是运行时异常(这不是Javascript, Ruby,……):-))
- This implementation is less efficient compared to the handwritten version (for any type)
- 与手写版本相比,这种实现的效率更低(对于任何类型)
On the other hand. What do you think Max should return when x and y are equivalents?
另一方面。当x和y相等时,你认为Max应该返回什么?
I'm starting to analyze Real-Generic implementations....
我开始分析Real-Generic实现....
The ideal implementation would be something like...
理想的实现应该是……
public static T Max<T>(T x, T y, Func<T, T, int> cmp)
{
return (cmp(x, y) > 0) ? x : y;
}
//Pseudo-code ( note the 'or' next to 'where' )
public static T Max<T>(T x, T y) where T: IComparable<T> or IComparable
{
return Max(x, y, (a, b) => { return a.CompareTo(b); });
}
This is not possible in C#, the next try is could be...
这在c#中是不可能的,下一个尝试是……
//pseudo-code
public static T Max<T>(T x, T y, Func<T, T, int> cmp)
{
return (cmp(x, y) > 0) ? x : y;
}
public static T Max<T>(T x, T y) where T: IComparable<T>
{
return Max(x, y, (a, b) => { return a.CompareTo(b); });
}
public static T Max<T>(T x, T y) where T: IComparable
{
return Max(x, y, (a, b) => { return a.CompareTo(b); });
}
But, this is neither possible, because overload resolution doesn't takes into account Generics Constraints....
但是,这既不可能,因为重载决议不考虑泛型约束....
Then, I'll leave out IComparable
consciously. I'm just going to worry about IComparable<T>
然后,我会有意识地省略掉这个词。我只关心icom克莱伯
public static T Max<T>(T x, T y, Func<T, T, int> cmp)
{
return (cmp(x, y) > 0) ? x : y;
}
public static T Max<T>(T x, T y) where T: IComparable<T>
{
return Max(x, y, (a, b) => { return a.CompareTo(b); });
}
#4
3
This is a little too late, but why not use dynamic types and delegates as an alternative to IComparable? This way you get compile-type safety in most cases and will only get a runtime error when the types supplied both do not support the operator < and you fail to provide the default comparer as an argument.
这有点太晚了,但是为什么不使用动态类型和委托作为icom寓言的替代呢?这样,您在大多数情况下都可以获得编译类型的安全性,并且只有在提供的类型不支持操作符 <并且您没有提供默认比较器作为参数时才会出现运行时错误。< p>
public static T Max<T>(T first, T second, Func<T,T,bool> f = null)
{
Func<dynamic,dynamic,bool> is_left_smaller = (x, y) => x < y ? true : false;
var compare = f ?? new Func<T, T, bool>((x, y) => is_left_smaller(x, y));
return compare(first, second) ? second : first;
}
#5
0
From memory, T also needs to be IComparable
(add that to the where
), and then you use v1.CompareTo(v2) > 0
etc.
根据记忆,T也需要是icom亦有味的(把它加到where),然后使用v1.CompareTo(v2) >等等。
#1
22
If you only want to create comparison functions then you could use the default comparer for the type T
. For example:
如果您只想创建比较函数,那么您可以使用默认比较器对类型t进行比较。
public static T Max<T>(T x, T y)
{
return (Comparer<T>.Default.Compare(x, y) > 0) ? x : y;
}
If T
implements IComparable<T>
then that comparer will be used; if T
doesn't implement IComparable<T>
but does implement IComparable
then that comparer will be used; if T
doesn't implement either IComparable<T>
or IComparable
then a runtime exception will be thrown.
如果T实现了icom克莱伯
If you want/need to do more than just compare the items then you could have a look at the generic operators implementation in MiscUtil and the related article.
如果您想/需要做的不仅仅是比较项目,那么您可以查看一下MiscUtil中的泛型操作符实现和相关文章。
#2
22
You probably want to constrain the generic types to implement IComparable
:
您可能想要约束泛型类型来实现icom寓言:
public T Max<T>(T v1, T v2) where T: struct, IComparable<T>
and then use the CompareTo
method:
然后使用CompareTo方法:
{
return (v1.CompareTo(v2) > 0 ? v1 : v2);
}
#3
4
Let me disagree. The @LukeH's implementation is not Generic.
我不同意。@卢克的实现不是通用的。
I will explain why it is not Generic:
我会解释为什么它不是通用的:
Comparer<T>.Default
involves inspecting T at run-time to determine if it implements IComparable<T>
, IComparable
or neither. Although this behavior is not well documented in http://msdn.microsoft.com/en-us/library/azhsac5f.aspx, we can deduct it because Comparer<T>.Default
throws an exception when T does not implement neither. If the inspection was done at compilation-time there would be no need for an exception (runtime), with an compile-time error would suffice.
比较器< T >。默认情况包括在运行时检查T,以确定它是否实现了icom亦步亦趋的
Then, as Comparer<T>.Default
uses Reflection, this means a high cost on Run-Time, then...., It is NOT Generic... Why?
然后,当比较器< T >。默认使用反射,这意味着高成本运行,然后....,它不是通用的……为什么?
Because Generic Programming means: A single algorithm (Generic) can cover many implementations (for many types) maintaining efficiency of hand-written versions.
因为泛型编程意味着:单个算法(泛型)可以覆盖许多实现(对于许多类型),从而保持手写版本的效率。
Take an example. The handwritten version for integers would be:
举一个例子。手写的整数版本是:
public static int Max( int x, int y)
{
return (x.CompareTo(y) > 0) ? x : y;
}
It is very simple, involving only a comparison (or maybe more, depending on how Int32.CompareTo() is implemented). If we use the @LukeH's implementation, we are adding Reflection to something that is very simple.
它非常简单,只涉及比较(或者更多,取决于Int32.CompareTo()的实现方式)。如果我们使用@卢克的实现,我们就为非常简单的东西添加了反射。
In short:
简而言之:
- Always prefer Compilation-time errors to Run-Time Exceptions ( this is not Javascript, Ruby,... :-) )
- 总是喜欢编译时错误而不是运行时异常(这不是Javascript, Ruby,……):-))
- This implementation is less efficient compared to the handwritten version (for any type)
- 与手写版本相比,这种实现的效率更低(对于任何类型)
On the other hand. What do you think Max should return when x and y are equivalents?
另一方面。当x和y相等时,你认为Max应该返回什么?
I'm starting to analyze Real-Generic implementations....
我开始分析Real-Generic实现....
The ideal implementation would be something like...
理想的实现应该是……
public static T Max<T>(T x, T y, Func<T, T, int> cmp)
{
return (cmp(x, y) > 0) ? x : y;
}
//Pseudo-code ( note the 'or' next to 'where' )
public static T Max<T>(T x, T y) where T: IComparable<T> or IComparable
{
return Max(x, y, (a, b) => { return a.CompareTo(b); });
}
This is not possible in C#, the next try is could be...
这在c#中是不可能的,下一个尝试是……
//pseudo-code
public static T Max<T>(T x, T y, Func<T, T, int> cmp)
{
return (cmp(x, y) > 0) ? x : y;
}
public static T Max<T>(T x, T y) where T: IComparable<T>
{
return Max(x, y, (a, b) => { return a.CompareTo(b); });
}
public static T Max<T>(T x, T y) where T: IComparable
{
return Max(x, y, (a, b) => { return a.CompareTo(b); });
}
But, this is neither possible, because overload resolution doesn't takes into account Generics Constraints....
但是,这既不可能,因为重载决议不考虑泛型约束....
Then, I'll leave out IComparable
consciously. I'm just going to worry about IComparable<T>
然后,我会有意识地省略掉这个词。我只关心icom克莱伯
public static T Max<T>(T x, T y, Func<T, T, int> cmp)
{
return (cmp(x, y) > 0) ? x : y;
}
public static T Max<T>(T x, T y) where T: IComparable<T>
{
return Max(x, y, (a, b) => { return a.CompareTo(b); });
}
#4
3
This is a little too late, but why not use dynamic types and delegates as an alternative to IComparable? This way you get compile-type safety in most cases and will only get a runtime error when the types supplied both do not support the operator < and you fail to provide the default comparer as an argument.
这有点太晚了,但是为什么不使用动态类型和委托作为icom寓言的替代呢?这样,您在大多数情况下都可以获得编译类型的安全性,并且只有在提供的类型不支持操作符 <并且您没有提供默认比较器作为参数时才会出现运行时错误。< p>
public static T Max<T>(T first, T second, Func<T,T,bool> f = null)
{
Func<dynamic,dynamic,bool> is_left_smaller = (x, y) => x < y ? true : false;
var compare = f ?? new Func<T, T, bool>((x, y) => is_left_smaller(x, y));
return compare(first, second) ? second : first;
}
#5
0
From memory, T also needs to be IComparable
(add that to the where
), and then you use v1.CompareTo(v2) > 0
etc.
根据记忆,T也需要是icom亦有味的(把它加到where),然后使用v1.CompareTo(v2) >等等。