Solution pour la contrainte d’opérateur surchargée dans les génériques .NET
-
02-07-2019 - |
Question
Que puis-je faire si je veux une méthode générique qui accepte uniquement les types ayant surchargé un opérateur, par exemple l'opérateur de soustraction. J'ai essayé d'utiliser une interface comme contrainte, mais les interfaces ne peuvent pas avoir de surcharge d'opérateurs.
Quel est le meilleur moyen d'y parvenir?
La solution
Il n'y a pas de réponse immédiate. les opérateurs sont statiques et ne peuvent pas être exprimés en contraintes - et les primitives existantes ne mettent en oeuvre aucune interface spécifique (contrairement à IComparable [< T >] qui peut être utilisé pour émuler une valeur supérieure à / inférieure -than).
Cependant; si vous voulez juste que cela fonctionne, alors, dans .NET 3.5, il y a quelques options ...
J'ai mis en place une bibliothèque ici qui permet de travailler efficacement et un accès simple aux opérateurs avec des génériques - tels que:
T result = Operator.Add(first, second); // implicit <T>; here
Il peut être téléchargé en tant que partie de MiscUtil
. De plus, en C # 4.0, cela devient possible via dynamic
:
static T Add<T>(T x, T y) {
dynamic dx = x, dy = y;
return dx + dy;
}
J'avais aussi (à un moment donné) une version .NET 2.0, mais celle-ci est moins testée. L’autre option consiste à créer une interface telle que
interface ICalc<T>
{
T Add(T,T)()
T Subtract(T,T)()
}
etc., mais vous devez ensuite passer un ICalc<T>;
toutes les méthodes, ce qui devient compliqué.
Autres conseils
J'ai constaté que l'IL pouvait très bien gérer cela. Ex.
ldarg.0
ldarg.1
add
ret
Compilé dans une méthode générique, le code fonctionnera correctement tant qu'un type primitif est spécifié. Il peut être possible d’étendre cela aux fonctions d’opérateur appelées sur des types non primitifs.
Voir ici .
Il y a un morceau de code volé des internats que j'utilise beaucoup pour cela. Il recherche ou construit à l'aide de IL
opérateurs arithmétiques de base. Tout cela est fait dans une classe générique Operation<T>
et tout ce que vous avez à faire est d’affecter l’opération requise à un délégué. Comme add = Operation<double>.Add
.
Il est utilisé comme ceci:
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"
}
}
<=> Le code source est une gracieuseté de paste bin: http://pastebin.com/nuqdeY8z
avec l'attribution ci-dessous:
/* 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.
*/