C# .NET泛型中重载运算符约束的解决方案

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/147646/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 15:34:37  来源:igfitidea点击:

Solution for overloaded operator constraint in .NET generics

提问by blackwing

What would I do if I want to have a generic method that only accepts types that have overloaded an operator, for instance the subtraction operator. I tried using an interface as a constraint but interfaces can't have operator overloading.

如果我想要一个只接受重载运算符的类型的泛型方法,例如减法运算符,我该怎么办。我尝试使用接口作为约束,但接口不能有运算符重载。

What is the best way to achieve this?

实现这一目标的最佳方法是什么?

采纳答案by Marc Gravell

There is no immediate answer; operators are static, and cannot be expressed in constraints - and the existing primatives don't implement any specific interface (contrast to IComparable[<T>] which can be used to emulate greater-than / less-than).

没有立即的答案;运算符是静态的,不能用约束来表达 - 并且现有的原语不实现任何特定的接口(与可用于模拟大于/小于的 IComparable[<T>] 形成对比)。

However; if you just want it to work, then in .NET 3.5 there are some options...

然而; 如果你只是想让它工作,那么在 .NET 3.5 中有一些选项......

I have put together a library herethat allows efficient and simple access to operators with generics - such as:

我在这里整理了一个库,允许高效且简单地访问具有泛型的运算符 - 例如:

T result = Operator.Add(first, second); // implicit <T>; here

It can be downloaded as part of MiscUtil

它可以作为MiscUtil 的一部分下载

Additionally, in C# 4.0, this becomes possible via dynamic:

此外,在 C# 4.0 中,这可以通过dynamic以下方式实现:

static T Add<T>(T x, T y) {
    dynamic dx = x, dy = y;
    return dx + dy;
}

I also had (at one point) a .NET 2.0 version, but that is less tested. The other option is to create an interface such as

我也有(曾经)一个 .NET 2.0 版本,但测试较少。另一种选择是创建一个接口,如

interface ICalc<T>
{
    T Add(T,T)() 
    T Subtract(T,T)()
} 

etc, but then you need to pass an ICalc<T>;through all the methods, which gets messy.

等等,但是你需要ICalc<T>;通过所有的方法,这会变得混乱。

回答by YellPika

I found that IL can actually handle this quite well. Ex.

我发现 IL 实际上可以很好地处理这个问题。前任。

ldarg.0
ldarg.1
add
ret

Compiled in a generic method, the code will run fine as long as a primitive type is specified. It may be possible to extend this to call operator functions on non-primitive types.

以泛型方法编译,只要指定了原始类型,代码就可以正常运行。可以将其扩展为在非原始类型上调用运算符函数。

See here.

这里

回答by ja72

There is a piece of code stolen from the internats that I use a lot for this. It looks for or builds using ILbasic arithmetic operators. It is all done within an Operation<T>generic class, and all you have to do is assign the required operation into a delegate. Like add = Operation<double>.Add.

有一段从内部人员那里偷来的代码,我为此经常使用它。它使用IL基本算术运算符查找或构建。这一切都在一个Operation<T>泛型类中完成,您所要做的就是将所需的操作分配给一个委托。喜欢add = Operation<double>.Add

It is used like this:

它是这样使用的:

public struct MyPoint
{
    public readonly double x, y;
    public MyPoint(double x, double y) { this.x=x; this.y=y; }
    // User types must have defined operators
    public static MyPoint operator+(MyPoint a, MyPoint b)
    {
        return new MyPoint(a.x+b.x, a.y+b.y);
    }
}
class Program
{
    // Sample generic method using Operation<T>
    public static T DoubleIt<T>(T a)
    {
        Func<T, T, T> add=Operation<T>.Add;
        return add(a, a);
    }

    // Example of using generic math
    static void Main(string[] args)
    {
        var x=DoubleIt(1);              //add integers, x=2
        var y=DoubleIt(Math.PI);        //add doubles, y=6.2831853071795862
        MyPoint P=new MyPoint(x, y);
        var Q=DoubleIt(P);              //add user types, Q=(4.0,12.566370614359172)

        var s=DoubleIt("ABC");          //concatenate strings, s="ABCABC"
    }
}

Operation<T>Source code courtesy of paste bin: http://pastebin.com/nuqdeY8z

Operation<T>源代码由粘贴箱提供:http: //pastebin.com/nuqdeY8z

with attribution below:

归属如下:

/* Copyright (C) 2007  The Trustees of Indiana University
 *
 * Use, modification and distribution is subject to the Boost Software
 * License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
 * http://www.boost.org/LICENSE_1_0.txt)
 *  
 * Authors: Douglas Gregor
 *          Andrew Lumsdaine
 *          
 * Url:     http://www.osl.iu.edu/research/mpi.net/svn/
 *
 * This file provides the "Operations" class, which contains common
 * reduction operations such as addition and multiplication for any
 * type.
 *
 * This code was heavily influenced by Keith Farmer's
 *   Operator Overloading with Generics
 * at http://www.codeproject.com/csharp/genericoperators.asp
 *
 * All MPI related code removed by ja72. 
 */