Есть ли ограничение, которое ограничивает мой общий метод численными типами?

c# generics constraints

89570 просмотра

19 ответа

Может ли кто-нибудь сказать мне, есть ли способ с дженериками, чтобы ограничивать аргумент общего типа Tтолько:

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

Я знаю whereключевое слово, но не могу найти интерфейс только для этих типов,

Что-то вроде:

static bool IntegerFunction<T>(T value) where T : INumeric 
Автор: Corin Blaikie Источник Размещён: 17.05.2019 03:23

Ответы (19)


122 плюса

Решение

Хейльсберг рассказал о причинах, по которым не удалось реализовать эту функцию в интервью с Брюсом Эккелем.

Я должен признать, однако, что я не знаю, как он думает, что его предлагаемое решение будет работать. Его предложение - отложить арифметические операции до какого-то другого родового класса (прочитайте интервью!). Как это помогает? ИМХО, не так много.

Автор: Konrad Rudolph Размещён: 29.08.2008 08:38

84 плюса

Учитывая популярность этого вопроса и интерес к такой функции, я с удивлением вижу, что ответа T4 пока нет.

В этом примере кода я продемонстрирую очень простой пример того, как вы можете использовать мощный механизм шаблонов, чтобы делать то, что компилятор в значительной степени делает за кулисами с помощью дженериков.

Вместо того, чтобы проходить обручи и жертвовать уверенностью в компиляции, вы можете просто сгенерировать нужную вам функцию для каждого типа, который вам нравится, и использовать его соответствующим образом (во время компиляции!).

Для этого:

  • Создайте новый файл текстового шаблона с именем GenericNumberMethodTemplate.tt .
  • Удалите автоматически сгенерированный код (вы сохраните большую часть его, но некоторые из них не нужны).
  • Добавьте следующий фрагмент:
<#@ 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;
        }
    <#
    } #>
}

Вот и все. Теперь все готово.

Сохранение этого файла автоматически скомпилирует его в этот исходный файл:

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;
    }
}

В вашем mainметоде вы можете убедиться, что у вас есть уверенность в компиляции:

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

введите описание изображения здесь

Я опережу одно замечание: нет, это не является нарушением принципа СУХОЙ. Принцип DRY заключается в том, чтобы люди не дублировали код в нескольких местах, что затрудняло бы поддержание приложения.

Это совсем не так: если вы хотите изменить, вы можете просто сменить шаблон (один источник для всего вашего поколения!), И все сделано.

Чтобы использовать его с вашими собственными определениями, добавьте декларацию пространства имен (убедитесь, что она такая же, как та, которая будет определять вашу собственную реализацию), в ваш сгенерированный код и пометьте класс как partial. Затем добавьте эти строки в файл шаблона, чтобы он был включен в возможную компиляцию:

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

Давайте будем честными: это довольно круто.

Отказ от ответственности: на этот образец в значительной степени повлияли Metaprogramming в .NET Кевином Хаззардом и Джейсоном Боком, Manning Publications .

Автор: Jeroen Vannevel Размещён: 15.03.2014 02:30

77 плюса

Для этого нет ограничений. Это реальная проблема для тех, кто хочет использовать generics для числовых вычислений.

Я пойду дальше и скажу, что нам нужно

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

Или даже

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

К сожалению, у вас есть только интерфейсы, базовые классы и ключевые слова struct(должен быть тип значения), class(должен быть ссылочным типом) и new()(должен иметь конструктор по умолчанию)

Вы можете обернуть число в нечто другое (похожее INullable<T>), как здесь, в codeproject .


Вы можете применить ограничение во время выполнения (путем отражения для операторов или проверки типов), но это действительно лишает преимущества наличия общего в первую очередь.

Автор: Keith Размещён: 28.08.2008 04:11

54 плюса

Обходное решение с использованием политик:

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();
}

Алгоритмы:

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;
    }

}

Использование:

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.

Решение является безопасным для компиляции. CityLizard Framework предоставляет скомпилированную версию для .NET 4.0. Файл - lib / NETFramework4.0 / CityLizard.Policy.dll.

Он также доступен в Nuget: https://www.nuget.org/packages/CityLizard/ . См. Структуру CityLizard.Policy.I .

Автор: Sergey Shandar Размещён: 28.01.2011 11:38

15 плюса

Этот вопрос - это немного FAQ, поэтому я размещаю это как wiki (так как раньше я писал подобное, но это более старый); тем не мение...

Какую версию .NET вы используете? Если вы используете .NET 3.5, то у меня есть реализация общих операторов в MiscUtil (бесплатно и т. Д.).

У этого есть методы, подобные T Add<T>(T x, T y), и другие варианты арифметики для разных типов (например DateTime + TimeSpan).

Кроме того, это работает для всех встроенных, снятых и сделанных на заказ операторов и кэширует делегата для выполнения.

Некоторые дополнительные сведения о том, почему это сложно, здесь .

Вы также можете знать, что dynamic(4.0) сортировка решает эту проблему косвенно - т.е.

dynamic x = ..., y = ...
dynamic result = x + y; // does what you expect
Автор: Marc Gravell Размещён: 12.08.2009 08:09

14 плюса

К сожалению, вы можете указать struct в предложении where в этом экземпляре. Кажется странным, что вы не можете указывать Int16, Int32 и т. Д., Но я уверен, что существует некоторая глубокая причина внедрения, лежащая в основе решения не допускать типы значений в предложении where.

Я думаю, единственное решение - выполнить проверку времени выполнения, которая, к сожалению, не позволяет решить проблему во время компиляции. Это будет похоже на:

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...
}

Который немного уродлив, я знаю, но, по крайней мере, обеспечивает требуемые ограничения.

Я также рассмотрел возможные последствия для этой реализации, возможно, есть более быстрый выход.

Автор: ljs Размещён: 28.08.2008 04:24

11 плюса

Вероятно, самое близкое, что вы можете сделать, это

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

Не уверен, можете ли вы сделать следующее

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

Для чего-то настолько специфического, почему бы просто не перегружать для каждого типа, список настолько короток и, возможно, меньше памяти.

Автор: Haacked Размещён: 28.08.2008 04:12

4 плюса

Невозможно ограничить типы шаблонов, но вы можете определить разные действия на основе типа. В качестве части общего числового пакета мне понадобился общий класс для добавления двух значений.

    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;
        }
    }

Обратите внимание, что typeofs оцениваются во время компиляции, поэтому операторы if будут удалены компилятором. Компилятор также удаляет ложные нажатия. Итак, что-то в компиляторе разрешило бы

        internal static int Sum(int first, int second)
        {
            return first + second;
        }
Автор: Rob Deary Размещён: 23.12.2014 07:53

3 плюса

Я создал небольшую библиотечную функциональность для решения этих проблем:

Вместо:

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.

Вы могли бы написать:

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.

Вы можете найти исходный код здесь: https://codereview.stackexchange.com/questions/26022/improvement-requested-for-generic-calculator-and-generic-number

Автор: Martin Mulder Размещён: 10.05.2013 11:15

2 плюса

Мне было интересно то же самое, что и samjudson, почему только целые числа? и если это так, вам может понадобиться создать вспомогательный класс или что-то подобное для хранения всех типов, которые вы хотите.

Если все, что вам нужно, это целые числа, не используйте общий, что не является общим; или еще лучше, отклоните любой другой тип, проверив его тип.

Автор: Martin Marconcini Размещён: 28.08.2008 04:14

1 плюс

В чем смысл упражнения?

Как уже указывали люди, у вас может быть функция, не имеющая общих функций, с наибольшим элементом, и компилятор автоматически преобразует меньшие значения для вас.

static bool IntegerFunction(Int64 value) { }

Если ваша функция находится на критическом по производительности пути (очень маловероятно, IMO), вы можете обеспечить перегрузку для всех необходимых функций.

static bool IntegerFunction(Int64 value) { }
...
static bool IntegerFunction(Int16 value) { }
Автор: dbkk Размещён: 28.08.2008 08:59

1 плюс

Я бы использовал общий, который вы могли бы обрабатывать внешним ...

/// <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;
}
Автор: Marc Roussel Размещён: 14.01.2010 03:53

1 плюс

Это ограничение повлияло на меня, когда я пытался перегрузить операторов для общих типов; так как не было ограничений «INumeric», и для множества других причин хорошие люди в stackoverflow с удовольствием предоставляют, операции не могут быть определены на общих типах.

Я хотел что-то вроде

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; };
    }
}

Я работал над этой проблемой с использованием динамического ввода времени .net4.

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 };
    }
}

Две вещи об использовании dynamic:

  1. Спектакль. Все типы значений получаются в коробке.
  2. Ошибки времени выполнения. Вы «били» компилятор, но теряете безопасность. Если общий тип не имеет определенного оператора, во время выполнения будет выбрано исключение.
Автор: pomeroy Размещён: 15.11.2010 08:52

1 плюс

Пока нет «хорошего» решения. Однако вы можете значительно сузить аргумент типа, чтобы исключить многие промахи для вашего гипотетического «INumeric» ограничения, как показало выше Haacked.

static bool IntegerFunction (значение T), где T: IComparable, IFormattable, IConvertible, IComparable , IEquatable , struct {...

Автор: dmihailescu Размещён: 01.07.2011 03:08

1 плюс

Типовые примитивные типы .NET не имеют общего интерфейса, который бы позволял использовать их для вычислений. Можно было бы определить свои собственные интерфейсы (например ISignedWholeNumber) , который будет выполнять такие операции, определить структуры , которые содержат один Int16, Int32и т.д. , и реализовывать эти интерфейсы, а затем методы , которые принимают общие типы ограниченных к ISignedWholeNumber, но имеющая для преобразования числовых значений к вашим типам структуры, вероятно, будет неприятность.

Альтернативный подход состоит в определении статического класса Int64Converter<T>со статическим свойством bool Available {get;};и статических делегатов для Int64 GetInt64(T value), T FromInt64(Int64 value), bool TryStoreInt64(Int64 value, ref T dest). Конструктор классов может быть жестко закодирован для загрузки делегатов для известных типов и, возможно, использовать Reflection для проверки того, Tреализует ли тип методы с именами и подписями (если это что-то вроде структуры, которая содержит a Int64и представляет число, но имеет пользовательский ToString()метод). Такой подход потеряет преимущества, связанные с проверкой типа времени компиляции, но все равно удастся избежать операций в боксе, и каждый тип нужно будет только «проверять» один раз. После этого операции, связанные с этим типом, будут заменены диспетчером делегирования.

Автор: supercat Размещён: 06.05.2013 03:44

1 плюс

Если вы используете .NET 4.0 и более поздние версии, вы можете просто использовать динамический аргумент метода и проверить во время выполнения, что переданный динамический тип аргумента является числовым / целочисленным типом.

Если тип прошедшего динамического значения не является числовым / целочисленным типом, то генерирует исключение.

Примерный короткий код, реализующий эту идею, выглядит примерно так:

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.
    }

Конечно, это решение работает только во время выполнения, но не во время компиляции.

Если вы хотите, чтобы решение всегда работало во время компиляции и никогда не было во время выполнения, вам придется обернуть динамик публичным struct / class, чьи перегруженные публичные конструкторы принимают аргументы только для желаемых типов и присваивают соответствующее имя struct / class.

Имеет смысл, что обернутая динамика всегда является частным членом класса / структуры и является единственным членом класса struct / class, а имя единственного члена struct / class - «значение».

Вам также необходимо будет определить и реализовать общедоступные методы и / или операторы, которые будут работать с нужными типами для частного динамического члена класса / структуры, если это необходимо.

Также имеет смысл, что struct / class имеет специальный / уникальный конструктор, который принимает динамический аргумент, который инициализирует его только частный динамический член с именем «value», но модификатор этого конструктора, конечно, является конфиденциальным .

После того, как класс / структура будет готов, определите тип аргумента IntegerFunction как тот класс / struct, который был определен.

Пример длинного кода, который реализует идею, выглядит примерно так:

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"
    }
}

Обратите внимание, что для использования динамического кода необходимо добавить ссылку на Microsoft.CSharp

Если версия .NET Framework ниже / меньше / меньше 4.0, а динамика не определена в этой версии, тогда вам придется использовать объект вместо этого и делать кастинг для целочисленного типа, что является проблемой, поэтому я рекомендую вам использовать в меньшей степени .NET 4.0 или новее, если вы можете так использовать динамический объект вместо объекта .

Автор: Farewell Stack Exchange Размещён: 19.08.2017 07:23

0 плюса

Если вы хотите использовать только один цифровой тип , вы можете подумать о создании чего-то похожего на псевдоним в C ++ using.

Поэтому вместо того, чтобы иметь очень общий

T ComputeSomething<T>(T value1, T value2) where T : INumeric { ... }

вы могли бы

using MyNumType = System.Double;
T ComputeSomething<MyNumType>(MyNumType value1, MyNumType value2) { ... }

Это может позволить вам легко перейти от doubleк intили другие , если это необходимо, но вы не могли бы использовать ComputeSomethingс doubleи intв одной и той же программе.

Но почему бы не заменить все doubleна intто? Потому что ваш метод может захотеть использовать doubleли вход doubleили int. Псевдоним позволяет вам точно знать, какая переменная использует динамический тип.

Автор: user276648 Размещён: 07.12.2018 05:49

-5 плюса

Нет единого интерфейса или базового класса, который все они наследуют (который не унаследован другими классами), поэтому простой ответ - нет.

Я действительно удивляюсь, почему это проблема. Что вы хотите сделать в своем классе IntegerFunction, который может быть сделан только для целых чисел?

Автор: samjudson Размещён: 28.08.2008 04:08

-9 плюса

Я думаю, вы недопонимаете дженерики. Если операция, которую вы пытаетесь выполнить, хороша только для конкретных типов данных, то вы не делаете что-то «общее».

Кроме того, поскольку вы хотите, чтобы функция работала только с типами данных int, вам не нужна отдельная функция для каждого конкретного размера. Простое использование параметра в самом большом конкретном типе позволит программе автоматически подгонять к нему более мелкие типы данных. (то есть передача Int16 будет автоматически конвертировать в Int64 при вызове).

Если вы выполняете разные операции на основе фактического размера int, передаваемого в функцию, я бы подумал, что вам следует серьезно пересмотреть, даже пытаясь сделать то, что вы делаете. Если вам нужно обмануть язык, вы должны думать немного больше о том, чего вы пытаетесь выполнить, а не о том, как делать то, что вы хотите.

В противном случае можно использовать параметр типа Object, а затем вам нужно будет проверить тип параметра и предпринять соответствующие действия или выбросить исключение.

Автор: Tom Welch Размещён: 28.08.2008 04:36
Вопросы из категории :
32x32