通用数学函数(Min, Max等)

时间:2021-08-26 20:01:58

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克莱伯 ,则使用比较器;如果T没有实现icom亦步亦趋的 ,但是实现了icom亦步亦趋的,则使用比较器;如果T不实现icom亦有梦的 或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亦步亦趋的 、icom亦步亦趋或两者都不实现。尽管这种行为在http://msdn.microsoft.com/en-us/library/azhsac5f.aspx中没有得到很好的记录,但是我们可以将其扣除,因为Comparer 。默认情况下,当T不实现这两个时,都会抛出异常。如果在编译时进行检查,就不需要异常(运行时),只要有编译时错误就足够了。

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:

简而言之:

  1. Always prefer Compilation-time errors to Run-Time Exceptions ( this is not Javascript, Ruby,... :-) )
  2. 总是喜欢编译时错误而不是运行时异常(这不是Javascript, Ruby,……):-))
  3. This implementation is less efficient compared to the handwritten version (for any type)
  4. 与手写版本相比,这种实现的效率更低(对于任何类型)

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克莱伯 ,则使用比较器;如果T没有实现icom亦步亦趋的 ,但是实现了icom亦步亦趋的,则使用比较器;如果T不实现icom亦有梦的 或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亦步亦趋的 、icom亦步亦趋或两者都不实现。尽管这种行为在http://msdn.microsoft.com/en-us/library/azhsac5f.aspx中没有得到很好的记录,但是我们可以将其扣除,因为Comparer 。默认情况下,当T不实现这两个时,都会抛出异常。如果在编译时进行检查,就不需要异常(运行时),只要有编译时错误就足够了。

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:

简而言之:

  1. Always prefer Compilation-time errors to Run-Time Exceptions ( this is not Javascript, Ruby,... :-) )
  2. 总是喜欢编译时错误而不是运行时异常(这不是Javascript, Ruby,……):-))
  3. This implementation is less efficient compared to the handwritten version (for any type)
  4. 与手写版本相比,这种实现的效率更低(对于任何类型)

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) >等等。