2008-08-28 4 views
279

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

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

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

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

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

ответ

113

Хейлсберг описал причины не реализации функции in an interview с Брюсом Эккель.

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

-5

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

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

+2

Интересно, почему у нескольких людей, отправляющих ответы здесь, было так много проблем с пониманием концепции. В моем случае я хочу делать &, - и ~ на любом типе целого числа или перечисления. Хорошо разработанные языки, такие как Scala, допускают такие дженерики. (Даже такие дрянные языки, как C++, допускают их.) – 2013-10-19 05:52:53

+1

Альтернативой было бы создание пользовательского класса и ограничение этого класса, а затем создание неявных операторов замещения для каждого из типов значений, которые вы хотите поддерживать. Вам нужно будет реализовать каждый из операторов &, - и ~, а также свой собственный класс ограничений. – samjudson 2013-10-21 08:20:41

72

Для этого нет ограничений. Это реальная проблема для тех, кто хочет использовать 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>), как here on codeproject.


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

+2

Интересно, видели ли вы поддержку MiscUtil для родовых операторов ... http://www.yoda.arachsys.com/csharp/miscutil/usage/genericoperators.html – 2009-08-12 20:03:57

+9

Да - Джон Скит указал мне на них что-то еще (но после ответа в этом году) - это умная идея, но мне все равно нужна поддержка с ограничениями. – Keith 2009-08-13 11:23:11

+1

Подождите, `где T: операторы (+, -, /, *)` является законным C#? Извините за вопрос о новичке. – kdbanman 2015-07-08 20:00:00

10

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

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> 

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

2

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

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

15

К сожалению, вы можете указать 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... 
} 

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

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

+11

+1, однако `// Остальная часть кода ...` не может компилироваться, если это зависит от операций, определенных ограничениями. – Nick 2012-09-10 14:23:50

+1

Convert.ToIntXX (значение) может помочь скомпилировать компиляцию «// остальной код» - по крайней мере, до тех пор, пока тип возвращаемого значения IntegerFunction также не будет иметь тип T, тогда вы будете обручены. :-p – yoyo 2014-07-08 06:32:14

+0

-1; это не работает по причине @Nick. В тот момент, когда вы пытаетесь выполнить какие-либо арифметические операции в `// Остатке кода ...`, например `value + value` или` value * value`, вы получаете ошибку компиляции. – 2017-10-25 21:15:03

-9

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

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

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

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

+10

Рассмотрите класс Гистограмма . Имеет смысл дать ему общий параметр, поэтому компилятор может оптимизировать его для байтов, ints, double, decimal, BigInt, ...но в то же время вам нужно предотвратить, что вы можете создать, скажем, гистограмму , потому что - разговаривая с Tron - она ​​не вычисляется. (буквально :)) – sunside 2010-05-11 22:14:33

1

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

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

static bool IntegerFunction(Int64 value) { } 

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

static bool IntegerFunction(Int64 value) { } 
... 
static bool IntegerFunction(Int16 value) { } 
16

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

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

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

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

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

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

dynamic x = ..., y = ... 
dynamic result = x + y; // does what you expect 
1

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

/// <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

Это ограничение повлияло на меня, когда я пытался перегрузить операторов для общих типов; так как не было ограничений «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. Performance. Все типы значений получаются в коробке.
  2. Ошибки времени выполнения. Вы «били» компилятор, но теряете безопасность. Если общий тип не имеет определенного оператора, во время выполнения будет выбрано исключение.
50

Обход с помощью политики:

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 структура.

1

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

статические BOOL IntegerFunction < Т > (значение Т), где Т: IComparable, IFormattable, IConvertible, IComparable < Т >, IEquatable <T>, структура {...

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 методы с собственными именами и сигнатурами (в случае, если это что-то вроде структуры, которая содержит Int64 и представляет собой число, но имеет пользовательский метод ToString()). Такой подход потеряет преимущества, связанные с проверкой типа времени компиляции, но все равно удастся избежать операций в боксе, и каждый тип нужно будет только «проверять» один раз. После этого операции, связанные с этим типом, будут заменены диспетчером делегирования.

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

72

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

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

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

Для того, чтобы сделать это:

  • Создать новый Text Template файл с именем 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(); 
     } 
    } 
} 

enter image description here

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

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

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

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

Давайте будем честны: Это довольно прохладно.

Отказ от ответственности: на этот образец в значительной степени повлиял Metaprogramming in .NET by Kevin Hazzard and Jason Bock, Manning Publications.

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 оцениваются во время компиляции, так что, если заявления будут удалены компилятором. Компилятор также удаляет ложные нажатия. Так что что-то будет решать в компилятор

 internal static int Sum(int first, int second) 
     { 
      return first + second; 
     } 
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/классом, перегружено общественные Конструкторов принимают аргументы желаемых типов только и укажите соответствующее имя структуры/класса.

Это имеет смысл, что завернуты динамический всегда частный член класса/структуры и является единственным членом структуры/класса и имя единственного члена структуры/класса «значение ».

Вам также необходимо определить и реализовать методы 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

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

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

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

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 и динамическая is undefi В этой версии вам придется использовать объект вместо этого и делать кастинг для целочисленного типа, что является проблемой, поэтому я рекомендую вам использовать хотя бы .NET 4.0 или новее, если вы можете так использовать динамический вместо этого от объект.

Смежные вопросы