¿Hay alguna restricción que restrinja mi método genérico a tipos numéricos?


¿Puede alguien decirme si hay una manera con genéricos de limitar un argumento de tipo genérico T a solo:

  • Int16
  • Int32
  • Int64
  • UInt16
  • UInt32
  • UInt64

Soy consciente de la palabra clave where, pero no puedo encontrar una interfaz para solo estos tipos,

Algo como:

static bool IntegerFunction<T>(T value) where T : INumeric 
Author: poke, 2008-08-28

18 answers

Hejlsberg ha descrito las razones para no implementar la característica en una entrevista con Bruce Eckel.

Tengo que admitir, sin embargo, que no se cómo piensa que su solución propuesta funcionará. Su propuesta es diferir las operaciones aritméticas a alguna otra clase genérica(lea la entrevista!). ¿Cómo ayuda esto? En mi humilde opinión, no mucho.

 122
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-29 08:38:25

Considerando la popularidad de esta pregunta y el interés detrás de tal función, me sorprende ver que todavía no hay una respuesta que involucre a T4.

En este código de ejemplo demostraré un ejemplo muy simple de cómo puede usar el potente motor de plantillas para hacer lo que el compilador hace prácticamente entre bastidores con los genéricos.

En lugar de ir a través de aros y sacrificar la certeza en tiempo de compilación, simplemente puede generar la función que desea para cada tipo que como y utilizar que en consecuencia (en tiempo de compilación!).

Para hacer esto:

  • Crear una nueva Plantilla de texto archivo llamado GenericNumberMethodTemplate.tt .
  • Elimine el código generado automáticamente (conservará la mayor parte de él, pero algunos no son necesarios).
  • Agregue el siguiente fragmento de código:
<#@ template language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>

<# Type[] types = new[] {
    typeof(Int16), typeof(Int32), typeof(Int64),
    typeof(UInt16), typeof(UInt32), typeof(UInt64)
    };
#>

using System;
public static class MaxMath {
    <# foreach (var type in types) { 
    #>
        public static <#= type.Name #> Max (<#= type.Name #> val1, <#= type.Name #> val2) {
            return val1 > val2 ? val1 : val2;
        }
    <#
    } #>
}

Eso es todo. Ya terminaste.

Guardar este archivo lo compilará automáticamente en este archivo fuente:

using System;
public static class MaxMath {
    public static Int16 Max (Int16 val1, Int16 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static Int32 Max (Int32 val1, Int32 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static Int64 Max (Int64 val1, Int64 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static UInt16 Max (UInt16 val1, UInt16 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static UInt32 Max (UInt32 val1, UInt32 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static UInt64 Max (UInt64 val1, UInt64 val2) {
        return val1 > val2 ? val1 : val2;
    }
}

En su main método puede verificar que tiene certeza en tiempo de compilación:

namespace TTTTTest
{
    class Program
    {
        static void Main(string[] args)
        {
            long val1 = 5L;
            long val2 = 10L;
            Console.WriteLine(MaxMath.Max(val1, val2));
            Console.Read();
        }
    }
}

introduzca la descripción de la imagen aquí

Me adelantaré a una observación: no, esto no es una violación del principio SECO. El principio DRY está ahí para evitar que las personas dupliquen código en varios lugares que causarían que la aplicación se volviera difícil de mantener.

Este no es el caso aquí: si desea un cambio, puede cambiar la plantilla (¡una sola fuente para toda su generación!) y está hecho.

En para usarlo con sus propias definiciones personalizadas, agregue una declaración de espacio de nombres (asegúrese de que sea la misma que la que definirá su propia implementación) a su código generado y marque la clase como partial. Luego, agrega estas líneas a tu archivo de plantilla para que se incluya en la compilación final:

<#@ import namespace="TheNameSpaceYouWillUse" #>
<#@ assembly name="$(TargetPath)" #>

Seamos honestos: Esto es bastante genial.

Descargo de responsabilidad: esta muestra ha sido fuertemente influenciada por Metaprogramación en. NET por Kevin Hazzard y Jason Bock, Manning Publications .

 82
Author: Jeroen Vannevel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-25 21:20:33

No hay ninguna restricción para esto. Es un problema real para cualquiera que quiera usar genéricos para cálculos numéricos.

Iría más lejos y diría que necesitamos

static bool GenericFunction<T>(T value) 
    where T : operators( +, -, /, * )

O incluso

static bool GenericFunction<T>(T value) 
    where T : Add, Subtract

Desafortunadamente solo tiene interfaces, clases base y las palabras clave struct (debe ser value-type), class (debe ser reference type) y new() (debe tener un constructor predeterminado)

Podría envolver el número en otra cosa (similar a INullable<T>) como aquí en codeproject .


Podría aplicar la restricción en tiempo de ejecución (reflejando para los operadores o comprobando los tipos), pero eso pierde la ventaja de tener el genérico en primer lugar.

 76
Author: Keith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-28 16:33:13

Solución alternativa mediante políticas:

interface INumericPolicy<T>
{
    T Zero();
    T Add(T a, T b);
    // add more functions here, such as multiplication etc.
}

struct NumericPolicies:
    INumericPolicy<int>,
    INumericPolicy<long>
    // add more INumericPolicy<> for different numeric types.
{
    int INumericPolicy<int>.Zero() { return 0; }
    long INumericPolicy<long>.Zero() { return 0; }
    int INumericPolicy<int>.Add(int a, int b) { return a + b; }
    long INumericPolicy<long>.Add(long a, long b) { return a + b; }
    // implement all functions from INumericPolicy<> interfaces.

    public static NumericPolicies Instance = new NumericPolicies();
}

Algoritmos:

static class Algorithms
{
    public static T Sum<P, T>(this P p, params T[] a)
        where P: INumericPolicy<T>
    {
        var r = p.Zero();
        foreach(var i in a)
        {
            r = p.Add(r, i);
        }
        return r;
    }

}

Uso:

int i = NumericPolicies.Instance.Sum(1, 2, 3, 4, 5);
long l = NumericPolicies.Instance.Sum(1L, 2, 3, 4, 5);
NumericPolicies.Instance.Sum("www", "") // compile-time error.

La solución es segura en tiempo de compilación. CityLizard Framework proporciona la versión compilada para.NET 4.0. El archivo es lib / NETFramework4.0 / CityLizard.Directiva.DLL.

También está disponible en Nuget: https://www.nuget.org/packages/CityLizard / . Véase CityLizard.Directiva.I estructura.

 53
Author: Sergey Shandar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-16 21:24:15

Esta pregunta es un poco de preguntas frecuentes, así que estoy publicando esto como wiki (ya que he publicado algo similar antes, pero este es uno más antiguo); de todos modos...

¿Qué versión de. NET está utilizando? Si está utilizando. NET 3.5, entonces tengo una implementación de operadores genéricos en MiscUtil (libre, etc.).

Esto tiene métodos como T Add<T>(T x, T y), y otras variantes para la aritmética en diferentes tipos (como DateTime + TimeSpan).

Además, esto funciona para todos los incorporados, levantados y hechos a medida y almacena en caché el delegado para el rendimiento.

Algunos antecedentes adicionales sobre por qué esto es complicado están aquí.

Es posible que también desee saber que dynamic (4.0) también resuelve este problema indirectamente, es decir,

dynamic x = ..., y = ...
dynamic result = x + y; // does what you expect
 16
Author: Marc Gravell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-12 20:15:11

Desafortunadamente solo puede especificar struct en la cláusula where en esta instancia. Parece extraño que no pueda especificar Int16, Int32, etc. específicamente, pero estoy seguro de que hay alguna razón de implementación profunda subyacente a la decisión de no permitir tipos de valor en una cláusula where.

Supongo que la única solución es hacer una comprobación de tiempo de ejecución que desafortunadamente evita que el problema se capte en tiempo de compilación. Eso sería algo como: -

static bool IntegerFunction<T>(T value) where T : struct {
  if (typeof(T) != typeof(Int16)  &&
      typeof(T) != typeof(Int32)  &&
      typeof(T) != typeof(Int64)  &&
      typeof(T) != typeof(UInt16) &&
      typeof(T) != typeof(UInt32) &&
      typeof(T) != typeof(UInt64)) {
    throw new ArgumentException(
      string.Format("Type '{0}' is not valid.", typeof(T).ToString()));
  }

  // Rest of code...
}

Que es un poco feo I saber, pero al menos proporciona las restricciones requeridas.

También me gustaría ver las posibles implicaciones de rendimiento para esta implementación, tal vez hay una manera más rápida por ahí.

 15
Author: ljs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-28 16:24:34

Probablemente lo más cercano que puedes hacer es

static bool IntegerFunction<T>(T value) where T: struct

No estoy seguro de si podría hacer lo siguiente

static bool IntegerFunction<T>(T value) where T: struct, IComparable
, IFormattable, IConvertible, IComparable<T>, IEquatable<T>

Para algo tan específico, por qué no tener sobrecargas para cada tipo, la lista es tan corta y posiblemente tendría menos espacio de memoria.

 10
Author: Haacked,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-28 16:12:33

No hay forma de restringir las plantillas a tipos, pero puede definir diferentes acciones en función del tipo. Como parte de un paquete numérico genérico, necesitaba una clase genérica para agregar dos valores.

    class Something<TCell>
    {
        internal static TCell Sum(TCell first, TCell second)
        {
            if (typeof(TCell) == typeof(int))
                return (TCell)((object)(((int)((object)first)) + ((int)((object)second))));

            if (typeof(TCell) == typeof(double))
                return (TCell)((object)(((double)((object)first)) + ((double)((object)second))));

            return second;
        }
    }

Tenga en cuenta que los typeofs se evalúan en tiempo de compilación, por lo que las sentencias if serían eliminadas por el compilador. El compilador también elimina los casts espurios. Así que algo se resolvería en el compilador a

        internal static int Sum(int first, int second)
        {
            return first + second;
        }
 4
Author: Rob Deary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-23 19:53:38

He creado una pequeña funcionalidad de biblioteca para resolver estos problemas:

En lugar de:

public T DifficultCalculation<T>(T a, T b)
{
    T result = a * b + a; // <== WILL NOT COMPILE!
    return result;
}
Console.WriteLine(DifficultCalculation(2, 3)); // Should result in 8.

Podrías escribir:

public T DifficultCalculation<T>(Number<T> a, Number<T> b)
{
    Number<T> result = a * b + a;
    return (T)result;
}
Console.WriteLine(DifficultCalculation(2, 3)); // Results in 8.

Puede encontrar el código fuente aquí: https://codereview.stackexchange.com/questions/26022/improvement-requested-for-generic-calculator-and-generic-number

 3
Author: Martin Mulder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-26 14:20:03

Me preguntaba lo mismo que samjudson, ¿por qué solo a enteros? y si ese es el caso, es posible que desee crear una clase auxiliar o algo así para contener todos los tipos que desee.

Si todo lo que desea son enteros, no use un genérico, que no es genérico; o mejor aún, rechace cualquier otro tipo marcando su tipo.

 2
Author: Martin Marconcini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-28 16:14:20

¿Cuál es el punto del ejercicio?

Como la gente ya ha señalado, podría tener una función no genérica que tome el elemento más grande, y el compilador convertirá automáticamente ints más pequeños para usted.

static bool IntegerFunction(Int64 value) { }

Si su función está en una ruta crítica de rendimiento (muy improbable, IMO), podría proporcionar sobrecargas para todas las funciones necesarias.

static bool IntegerFunction(Int64 value) { }
...
static bool IntegerFunction(Int16 value) { }
 1
Author: dbkk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-28 20:59:00

Usaría uno genérico que podría manejar externamente...

/// <summary>
/// Generic object copy of the same type
/// </summary>
/// <typeparam name="T">The type of object to copy</typeparam>
/// <param name="ObjectSource">The source object to copy</param>
public T CopyObject<T>(T ObjectSource)
{
    T NewObject = System.Activator.CreateInstance<T>();

    foreach (PropertyInfo p in ObjectSource.GetType().GetProperties())
        NewObject.GetType().GetProperty(p.Name).SetValue(NewObject, p.GetValue(ObjectSource, null), null);

    return NewObject;
}
 1
Author: Marc Roussel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-14 15:53:39

Esta limitación me afectó cuando traté de sobrecargar los operadores para los tipos genéricos; ya que no había ninguna restricción "inumerica", y por un grupo de otras razones las buenas personas en stackoverflow están felices de proporcionar, las operaciones no se pueden definir en los tipos genéricos.

Quería algo como

public struct Foo<T>
{
    public T Value{ get; private set; }

    public static Foo<T> operator +(Foo<T> LHS, Foo<T> RHS)
    {
        return new Foo<T> { Value = LHS.Value + RHS.Value; };
    }
}

He solucionado este problema usando .net4 dynamic runtime typing.

public struct Foo<T>
{
    public T Value { get; private set; }

    public static Foo<T> operator +(Foo<T> LHS, Foo<T> RHS)
    {
        return new Foo<T> { Value = LHS.Value + (dynamic)RHS.Value };
    }
}

Las dos cosas acerca de usar dynamic son

  1. Rendimiento. Todos los tipos de valor get en caja.
  2. Errores de tiempo de ejecución. "Le ganas" al compilador, pero pierdes la seguridad de tipo. Si el tipo genérico no tiene el operador definido, se lanzará una excepción durante la ejecución.
 1
Author: pomeroy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-16 16:41:45

Todavía no hay una solución 'buena' para esto. Sin embargo, puede limitar el argumento de tipo significativamente para descartar muchos errores de error para su restricción hipotética 'inumerica' como Haacked ha mostrado anteriormente.

Static bool IntegerFunction(valor T) donde T: IComparable, IFormattable, IConvertible, IComparable, IEquatable, struct {...

 1
Author: dmihailescu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-01 15:17:20

Los tipos primitivos numéricos.NET no comparten ninguna interfaz común que les permita ser utilizados para cálculos. Sería posible definir sus propias interfaces (por ejemplo, ISignedWholeNumber) que realizarían tales operaciones, definir estructuras que contengan un único Int16, Int32, etc. e implementar esas interfaces, y luego tener métodos que aceptan tipos genéricos restringidos a ISignedWholeNumber, pero tener que convertir valores numéricos a sus tipos de estructura probablemente sería una molestia.

An el enfoque alternativo sería definir la clase estática Int64Converter<T> con una propiedad estática bool Available {get;}; y delegados estáticos para Int64 GetInt64(T value), T FromInt64(Int64 value), bool TryStoreInt64(Int64 value, ref T dest). El constructor de clases podría usar ser codificado para cargar delegados para tipos conocidos, y posiblemente usar Reflexión para probar si type T implementa métodos con los nombres propios y las firmas (en caso de que sea algo así como una estructura que contiene un Int64 y representa un número, pero tiene un método personalizado ToString()). Este enfoque perdería las ventajas asociado con la verificación de tipos en tiempo de compilación, pero aún así lograría evitar las operaciones de boxeo y cada tipo solo tendría que ser "verificado" una vez. Después de eso, las operaciones asociadas con ese tipo se reemplazarían con un envío delegado.

 1
Author: supercat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-06 15:44:04

Si está utilizando.NET 4.0 y versiones posteriores, puede usar dynamic como argumento de método y comprobar en tiempo de ejecución que el tipo de argumento dynamic pasado es de tipo numérico/entero.

Si el tipo del dinámico pasado es no numérico/entero, entonces lanzar excepción.

Un ejemplo código corto que implementa la idea es algo así como:

using System;
public class InvalidArgumentException : Exception
{
    public InvalidArgumentException(string message) : base(message) {}
}
public class InvalidArgumentTypeException : InvalidArgumentException
{
    public InvalidArgumentTypeException(string message) : base(message) {}
}
public class ArgumentTypeNotIntegerException : InvalidArgumentTypeException
{
    public ArgumentTypeNotIntegerException(string message) : base(message) {}
}
public static class Program
{
    private static bool IntegerFunction(dynamic n)
    {
        if (n.GetType() != typeof(Int16) &&
            n.GetType() != typeof(Int32) &&
            n.GetType() != typeof(Int64) &&
            n.GetType() != typeof(UInt16) &&
            n.GetType() != typeof(UInt32) &&
            n.GetType() != typeof(UInt64))
            throw new ArgumentTypeNotIntegerException("argument type is not integer type");
        //code that implements IntegerFunction goes here
    }
    private static void Main()
    {
         Console.WriteLine("{0}",IntegerFunction(0)); //Compiles, no run time error and first line of output buffer is either "True" or "False" depends on the code that implements "Program.IntegerFunction" static method.
         Console.WriteLine("{0}",IntegerFunction("string")); //Also compiles but it is run time error and exception of type "ArgumentTypeNotIntegerException" is thrown here.
         Console.WriteLine("This is the last Console.WriteLine output"); //Never reached and executed due the run time error and the exception thrown on the second line of Program.Main static method.
    }

Por supuesto que esta solución solo funciona en tiempo de ejecución, pero nunca en compilación tiempo.

Si desea una solución que siempre funcione en tiempo de compilación y nunca en tiempo de ejecución, entonces tendrá que envolver el dinámico con una estructura/clase pública cuyos constructores sobrecargados públicos solo aceptan argumentos de los tipos deseados y le dan el nombre apropiado a la estructura/clase.

Tiene sentido que el envuelto dinámico es siempre privado miembro de la clase / estructura y es el único miembro de la estructura / clase y el nombre de la única el miembro de la struct / class es "value".

También tendrá que definir e implementar métodos y/o operadores públicos que funcionen con los tipos deseados para el miembro dinámico privado de la clase/estructura si es necesario.

También tiene sentido que la estructura / clase tenga constructor especial/único que acepte dinámico {[4] } como argumento que inicializa su único miembro dinámico privado llamado "valor", pero el modificador de este constructor es privado por supuesto.

Una vez que la clase/estructura está lista, defina el tipo de IntegerFunction del argumento como la clase/estructura que ha sido definida.

Un ejemplo código largo que implementa la idea es algo así como:

using System;
public struct Integer
{
    private dynamic value;
    private Integer(dynamic n) { this.value = n; }
    public Integer(Int16 n) { this.value = n; }
    public Integer(Int32 n) { this.value = n; }
    public Integer(Int64 n) { this.value = n; }
    public Integer(UInt16 n) { this.value = n; }
    public Integer(UInt32 n) { this.value = n; }
    public Integer(UInt64 n) { this.value = n; }
    public Integer(Integer n) { this.value = n.value; }
    public static implicit operator Int16(Integer n) { return n.value; }
    public static implicit operator Int32(Integer n) { return n.value; }
    public static implicit operator Int64(Integer n) { return n.value; }
    public static implicit operator UInt16(Integer n) { return n.value; }
    public static implicit operator UInt32(Integer n) { return n.value; }
    public static implicit operator UInt64(Integer n) { return n.value; }
    public static Integer operator +(Integer x, Int16 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, Int32 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, Int64 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, UInt16 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, UInt32 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, UInt64 y) { return new Integer(x.value + y); }
    public static Integer operator -(Integer x, Int16 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, Int32 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, Int64 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, UInt16 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, UInt32 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, UInt64 y) { return new Integer(x.value - y); }
    public static Integer operator *(Integer x, Int16 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, Int32 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, Int64 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, UInt16 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, UInt32 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, UInt64 y) { return new Integer(x.value * y); }
    public static Integer operator /(Integer x, Int16 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, Int32 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, Int64 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, UInt16 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, UInt32 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, UInt64 y) { return new Integer(x.value / y); }
    public static Integer operator %(Integer x, Int16 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, Int32 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, Int64 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, UInt16 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, UInt32 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, UInt64 y) { return new Integer(x.value % y); }
    public static Integer operator +(Integer x, Integer y) { return new Integer(x.value + y.value); }
    public static Integer operator -(Integer x, Integer y) { return new Integer(x.value - y.value); }
    public static Integer operator *(Integer x, Integer y) { return new Integer(x.value * y.value); }
    public static Integer operator /(Integer x, Integer y) { return new Integer(x.value / y.value); }
    public static Integer operator %(Integer x, Integer y) { return new Integer(x.value % y.value); }
    public static bool operator ==(Integer x, Int16 y) { return x.value == y; }
    public static bool operator !=(Integer x, Int16 y) { return x.value != y; }
    public static bool operator ==(Integer x, Int32 y) { return x.value == y; }
    public static bool operator !=(Integer x, Int32 y) { return x.value != y; }
    public static bool operator ==(Integer x, Int64 y) { return x.value == y; }
    public static bool operator !=(Integer x, Int64 y) { return x.value != y; }
    public static bool operator ==(Integer x, UInt16 y) { return x.value == y; }
    public static bool operator !=(Integer x, UInt16 y) { return x.value != y; }
    public static bool operator ==(Integer x, UInt32 y) { return x.value == y; }
    public static bool operator !=(Integer x, UInt32 y) { return x.value != y; }
    public static bool operator ==(Integer x, UInt64 y) { return x.value == y; }
    public static bool operator !=(Integer x, UInt64 y) { return x.value != y; }
    public static bool operator ==(Integer x, Integer y) { return x.value == y.value; }
    public static bool operator !=(Integer x, Integer y) { return x.value != y.value; }
    public override bool Equals(object obj) { return this == (Integer)obj; }
    public override int GetHashCode() { return this.value.GetHashCode(); }
    public override string ToString() { return this.value.ToString(); }
    public static bool operator >(Integer x, Int16 y) { return x.value > y; }
    public static bool operator <(Integer x, Int16 y) { return x.value < y; }
    public static bool operator >(Integer x, Int32 y) { return x.value > y; }
    public static bool operator <(Integer x, Int32 y) { return x.value < y; }
    public static bool operator >(Integer x, Int64 y) { return x.value > y; }
    public static bool operator <(Integer x, Int64 y) { return x.value < y; }
    public static bool operator >(Integer x, UInt16 y) { return x.value > y; }
    public static bool operator <(Integer x, UInt16 y) { return x.value < y; }
    public static bool operator >(Integer x, UInt32 y) { return x.value > y; }
    public static bool operator <(Integer x, UInt32 y) { return x.value < y; }
    public static bool operator >(Integer x, UInt64 y) { return x.value > y; }
    public static bool operator <(Integer x, UInt64 y) { return x.value < y; }
    public static bool operator >(Integer x, Integer y) { return x.value > y.value; }
    public static bool operator <(Integer x, Integer y) { return x.value < y.value; }
    public static bool operator >=(Integer x, Int16 y) { return x.value >= y; }
    public static bool operator <=(Integer x, Int16 y) { return x.value <= y; }
    public static bool operator >=(Integer x, Int32 y) { return x.value >= y; }
    public static bool operator <=(Integer x, Int32 y) { return x.value <= y; }
    public static bool operator >=(Integer x, Int64 y) { return x.value >= y; }
    public static bool operator <=(Integer x, Int64 y) { return x.value <= y; }
    public static bool operator >=(Integer x, UInt16 y) { return x.value >= y; }
    public static bool operator <=(Integer x, UInt16 y) { return x.value <= y; }
    public static bool operator >=(Integer x, UInt32 y) { return x.value >= y; }
    public static bool operator <=(Integer x, UInt32 y) { return x.value <= y; }
    public static bool operator >=(Integer x, UInt64 y) { return x.value >= y; }
    public static bool operator <=(Integer x, UInt64 y) { return x.value <= y; }
    public static bool operator >=(Integer x, Integer y) { return x.value >= y.value; }
    public static bool operator <=(Integer x, Integer y) { return x.value <= y.value; }
    public static Integer operator +(Int16 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(Int32 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(Int64 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(UInt16 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(UInt32 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(UInt64 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator -(Int16 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(Int32 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(Int64 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(UInt16 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(UInt32 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(UInt64 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator *(Int16 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(Int32 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(Int64 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(UInt16 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(UInt32 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(UInt64 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator /(Int16 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(Int32 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(Int64 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(UInt16 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(UInt32 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(UInt64 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator %(Int16 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(Int32 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(Int64 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(UInt16 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(UInt32 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(UInt64 x, Integer y) { return new Integer(x % y.value); }
    public static bool operator ==(Int16 x, Integer y) { return x == y.value; }
    public static bool operator !=(Int16 x, Integer y) { return x != y.value; }
    public static bool operator ==(Int32 x, Integer y) { return x == y.value; }
    public static bool operator !=(Int32 x, Integer y) { return x != y.value; }
    public static bool operator ==(Int64 x, Integer y) { return x == y.value; }
    public static bool operator !=(Int64 x, Integer y) { return x != y.value; }
    public static bool operator ==(UInt16 x, Integer y) { return x == y.value; }
    public static bool operator !=(UInt16 x, Integer y) { return x != y.value; }
    public static bool operator ==(UInt32 x, Integer y) { return x == y.value; }
    public static bool operator !=(UInt32 x, Integer y) { return x != y.value; }
    public static bool operator ==(UInt64 x, Integer y) { return x == y.value; }
    public static bool operator !=(UInt64 x, Integer y) { return x != y.value; }
    public static bool operator >(Int16 x, Integer y) { return x > y.value; }
    public static bool operator <(Int16 x, Integer y) { return x < y.value; }
    public static bool operator >(Int32 x, Integer y) { return x > y.value; }
    public static bool operator <(Int32 x, Integer y) { return x < y.value; }
    public static bool operator >(Int64 x, Integer y) { return x > y.value; }
    public static bool operator <(Int64 x, Integer y) { return x < y.value; }
    public static bool operator >(UInt16 x, Integer y) { return x > y.value; }
    public static bool operator <(UInt16 x, Integer y) { return x < y.value; }
    public static bool operator >(UInt32 x, Integer y) { return x > y.value; }
    public static bool operator <(UInt32 x, Integer y) { return x < y.value; }
    public static bool operator >(UInt64 x, Integer y) { return x > y.value; }
    public static bool operator <(UInt64 x, Integer y) { return x < y.value; }
    public static bool operator >=(Int16 x, Integer y) { return x >= y.value; }
    public static bool operator <=(Int16 x, Integer y) { return x <= y.value; }
    public static bool operator >=(Int32 x, Integer y) { return x >= y.value; }
    public static bool operator <=(Int32 x, Integer y) { return x <= y.value; }
    public static bool operator >=(Int64 x, Integer y) { return x >= y.value; }
    public static bool operator <=(Int64 x, Integer y) { return x <= y.value; }
    public static bool operator >=(UInt16 x, Integer y) { return x >= y.value; }
    public static bool operator <=(UInt16 x, Integer y) { return x <= y.value; }
    public static bool operator >=(UInt32 x, Integer y) { return x >= y.value; }
    public static bool operator <=(UInt32 x, Integer y) { return x <= y.value; }
    public static bool operator >=(UInt64 x, Integer y) { return x >= y.value; }
    public static bool operator <=(UInt64 x, Integer y) { return x <= y.value; }
}
public static class Program
{
    private static bool IntegerFunction(Integer n)
    {
        //code that implements IntegerFunction goes here
        //note that there is NO code that checks the type of n in rum time, because it is NOT needed anymore 
    }
    private static void Main()
    {
        Console.WriteLine("{0}",IntegerFunction(0)); //compile error: there is no overloaded METHOD for objects of type "int" and no implicit conversion from any object, including "int", to "Integer" is known.
        Console.WriteLine("{0}",IntegerFunction(new Integer(0))); //both compiles and no run time error
        Console.WriteLine("{0}",IntegerFunction("string")); //compile error: there is no overloaded METHOD for objects of type "string" and no implicit conversion from any object, including "string", to "Integer" is known.
        Console.WriteLine("{0}",IntegerFunction(new Integer("string"))); //compile error: there is no overloaded CONSTRUCTOR for objects of type "string"
    }
}

Tenga en cuenta que para usar dynamicen su código debe Agregar Referenciaa Microsoft.CSharp

Si la versión de. NET framework está por debajo de/under/menor que 4.0 y dynamic es undefined en esa versión, entonces tendrá que usar object en su lugar y hacer casting al tipo entero, lo cual es problemático, por lo que le recomiendo que use al menos.NET 4.0 o más reciente si puede, para que pueda usar dynamic en lugar de object .

 1
Author: Farewell Stack Exchange,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-19 19:35:28

No hay una única interfaz o clase base que todos hereden (que no es también heredada por otras clases) por lo que la respuesta simple es no.

Me pregunto por qué es un problema. ¿Qué quieres hacer dentro de tu clase IntegerFunction que solo se puede hacer a enteros?

 -5
Author: samjudson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-28 16:08:57

Creo que está malinterpretando los genéricos. Si la operación que está tratando de realizar solo es buena para tipos de datos específicos, entonces no está haciendo algo "genérico".

Además, dado que solo desea permitir que la función funcione en tipos de datos int, no debería necesitar una función separada para cada tamaño específico. Simplemente tomar un parámetro en el tipo específico más grande permitirá al programa transmitir automáticamente los tipos de datos más pequeños a él. (es decir, pasar una voluntad Int16 auto-convertir a Int64 al llamar).

Si está realizando diferentes operaciones basadas en el tamaño real de int que se pasa a la función, entonces creo que debería reconsiderar seriamente incluso tratando de hacer lo que está haciendo. Si tiene que engañar al lenguaje, debe pensar un poco más en lo que está tratando de lograr en lugar de cómo hacer lo que desea.

Fallando todo lo demás, se podría usar un parámetro de tipo Object y luego tendrá que verificar el tipo de parameter and take appropriate action or throw an exception.

 -9
Author: Tom Welch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-08-28 16:36:36