Czy istnieje ograniczenie, które ogranicza moją metodę generyczną do typów numerycznych?

Czy ktoś może mi powiedzieć, czy istnieje sposób z generykami, aby ograniczyć argument typu ogólnego T Tylko do:

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

Znam słowo kluczowe where, ale nie mogę znaleźć interfejsu dla tylko tych typów,

Coś w stylu:

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

18 answers

Hejlsberg opisał przyczyny braku implementacji funkcji w wywiadzie z Bruce ' em Eckelem.

Muszę jednak przyznać, że nie wiem, jak on myśli, że jego proponowane obejście będzie działać. Jego propozycją jest przesunięcie operacji arytmetycznych do innej klasy ogólnej (przeczytaj Wywiad!). Jak to ma pomóc? IMHO, niewiele.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-29 08:38:25

Biorąc pod uwagę popularność tego pytania i zainteresowanie taką funkcją, jestem zaskoczony, że nie ma jeszcze odpowiedzi dotyczącej T4.

W tym przykładowym kodzie zademonstruję bardzo prosty przykład użycia potężnego silnika szablonów do robienia tego, co kompilator robi za kulisami z generykami.

Zamiast przechodzić przez obręcze i poświęcać pewność kompilacji, możesz po prostu wygenerować żądaną funkcję dla każdego typu Polub i użyj tego odpowiednio (w czasie kompilacji!).

Aby to zrobić:

  • Utwórz nowy szablon tekstowy plik o nazwie GenericNumberMethodTemplate.tt .
  • Usuń automatycznie wygenerowany kod (zachowasz większość, ale część nie jest potrzebna).
  • Dodaj następujący fragment:
<#@ 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;
        }
    <#
    } #>
}
To wszystko. Już po tobie.

Zapisanie tego pliku automatycznie skompiluje go do tego pliku źródłowego:

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

W Twoim main metoda możesz sprawdzić, czy masz pewność w czasie kompilacji:

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

Tutaj wpisz opis obrazka

Uprzedzę jedną uwagę: nie, to nie jest naruszenie zasady suchej. Zasada DRY polega na tym, aby zapobiec powielaniu kodu w wielu miejscach, które spowodowałyby, że aplikacja stanie się trudna do utrzymania.

Tutaj w ogóle tak nie jest: jeśli chcesz zmiany, możesz po prostu zmienić szablon (Jedno źródło dla całego pokolenia!) i gotowe.

W aby użyć go z własnymi definicjami, dodaj deklarację przestrzeni nazw (upewnij się, że jest taka sama jak ta, w której zdefiniujesz własną implementację) do wygenerowanego kodu i oznacz klasę jako partial. Następnie dodaj te linie do pliku szablonu, aby znalazły się w ostatecznej kompilacji:

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

Bądźmy szczerzy: to jest całkiem fajne.

[[6]}Zastrzeżenie: Ta próbka była pod silnym wpływem Metaprogramowania w. NET przez Kevina Hazzarda i Jasona 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-25 21:20:33

Nie ma na to żadnych ograniczeń. To prawdziwy problem dla każdego, kto chce używać generyków do obliczeń numerycznych.

Poszedłbym dalej i powiedział, że potrzebujemy

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

Lub nawet

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

Niestety masz tylko interfejsy, klasy bazowe i słowa kluczowe struct (musi być value-type), class (musi być reference type) I new() (musi mieć domyślny konstruktor)

Możesz zawinąć numer w coś innego (podobnego do INullable<T>) Jak tutaj na codeproject .


Możesz zastosować ograniczenie w czasie wykonywania (poprzez rozważenie operatorów lub sprawdzenie typów), ale to traci przewagę posiadania generycznego w pierwszej kolejności.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-28 16:33:13

Obejście przy użyciu zasad:

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

Algorytmy:

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

}

Użycie:

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.

Rozwiązanie jest bezpieczne w czasie kompilacji. CityLizard Framework dostarcza skompilowaną wersję dla. NET 4.0. Plik to lib / NETFramework4.0 / CityLizard.Polityka.dll.

Jest również dostępny w Nuget: https://www.nuget.org/packages/CityLizard / . Zobacz .Polityka.I struktura.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-16 21:24:15

To pytanie jest trochę FAQ, więc zamieszczam to jako wiki( ponieważ wcześniej pisałem podobne, ale to jest starsze); w każdym razie...

Jakiej wersji. NET używasz? Jeśli używasz. NET 3.5, to mam implementację operatorów generycznych W MiscUtil (free etc).

To ma metody jak T Add<T>(T x, T y), i inne warianty dla arytmetyki na różnych typach (jak DateTime + TimeSpan).

Dodatkowo działa to dla wszystkich wbudowanych, podnoszonych i dostosowanych do potrzeb operatorów i buforuje delegata do wykonania.

Niektóre dodatkowe informacje o tym, dlaczego jest to trudne jest tutaj .

Możesz też chcieć wiedzieć, że dynamic (4.0) sort - of rozwiązuje również ten problem pośrednio - tj.

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/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-12 20:15:11

Niestety w tym przypadku możesz określić tylko strukturę w klauzuli where. Wydaje się to dziwne, że nie można podać Int16, Int32, itd. w szczególności, ale jestem pewien, że jest jakiś głęboki powód implementacji leżący u podstaw decyzji, aby nie zezwalać na typy wartości w klauzuli where.

Myślę, że jedynym rozwiązaniem jest sprawdzenie środowiska uruchomieniowego, które Niestety zapobiega wychwytywaniu problemu podczas kompilacji. To by było coś w stylu: -

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

Który jest trochę brzydki I wiem, ale przynajmniej zapewnia wymagane ograniczenia.

Przyjrzałbym się również możliwym implikacjom wydajności dla tej implementacji, być może istnieje szybsze wyjście.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-28 16:24:34

Prawdopodobnie najbliżej jest

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

Nie jestem pewien, czy możesz wykonać następujące czynności

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

Dla czegoś tak specyficznego, dlaczego nie mieć przeciążeń dla każdego typu, lista jest tak krótka i prawdopodobnie miałaby mniej pamięci.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-28 16:12:33

Nie ma możliwości ograniczenia szablonów do typów, ale można zdefiniować różne akcje w zależności od typu. Jako część generycznego pakietu numerycznego, potrzebowałem klasy generycznej, aby dodać dwie wartości.

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

Zauważ, że typeofs są oceniane w czasie kompilacji, więc polecenia if byłyby usuwane przez kompilator. Kompilator usuwa również sfałszowane odlewy. Więc coś rozwiązałoby się w kompilatorze do

        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/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-23 19:53:38

Stworzyłem małą funkcjonalność biblioteki, aby rozwiązać te problemy:

Zamiast:

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.
Możesz napisać:
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.

Możesz znaleźć kod źródłowy tutaj: 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-26 14:20:03

Zastanawiałem się tak samo jak samjudson, dlaczego tylko do liczb całkowitych? a jeśli tak jest, możesz chcieć utworzyć klasę pomocniczą lub coś w tym stylu, aby trzymać wszystkie typy, które chcesz.

Jeśli wszystko, co chcesz, to liczby całkowite, nie używaj generycznego, który nie jest generyczny; lub jeszcze lepiej, Odrzuć dowolny inny typ, sprawdzając jego typ.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-28 16:14:20

Jaki jest cel ćwiczenia?

Jak już ludzie zauważyli, możesz mieć niestandardową funkcję pobierającą największy element, a kompilator automatycznie konwertuje za Ciebie mniejsze int.

static bool IntegerFunction(Int64 value) { }

Jeśli twoja funkcja znajduje się na ścieżce krytycznej wydajności (bardzo mało prawdopodobne, IMO), możesz zapewnić przeciążenia wszystkich potrzebnych funkcji.

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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-28 20:59:00

Użyłbym ogólnego, który mógłbyś obsłużyć zewnętrznie...

/// <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/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-14 15:53:39

To ograniczenie wpłynęło na mnie, gdy próbowałem przeciążać operatorów dla typów generycznych; ponieważ nie było ograniczeń "Nieumerycznych" i z wielu innych powodów dobrzy ludzie w stackoverflow chętnie zapewniają, operacje nie mogą być zdefiniowane na typach generycznych.

I wanted something like

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

Obejrzałem ten problem używając .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 };
    }
}

Dwie rzeczy o użyciu dynamic to

  1. Wydajność. Wszystkie typy wartości get w pudełku.
  2. błędy uruchomieniowe. "Pokonujesz" kompilator, ale tracisz bezpieczeństwo typu. Jeśli Typ generyczny nie ma zdefiniowanego operatora, podczas wykonywania zostanie wyrzucony wyjątek.
 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/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-16 16:41:45

Nie ma na to jeszcze "dobrego" rozwiązania. Możesz jednak znacznie zawęzić argument typu, aby wykluczyć wiele missfitów dla hipotetycznego ograniczenia "Nieumerycznego", jak pokazano powyżej.

Static bool IntegerFunction (wartość T) gdzie T: IComparable, Iformattable, IComparable, 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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-01 15:17:20

Prymitywne typy numeryczne. NET nie mają wspólnego interfejsu, który pozwalałby na ich użycie do obliczeń. Możliwe byłoby zdefiniowanie własnych interfejsów (np. ISignedWholeNumber), które wykonywałyby takie operacje, definiowały struktury zawierające pojedynczy Int16, Int32, itd. i zaimplementować te interfejsy, a następnie mieć metody, które akceptują typy generyczne ograniczone do ISignedWholeNumber, ale konieczność konwersji wartości liczbowych na typy struktury prawdopodobnie byłaby uciążliwa.

An alternatywnym podejściem byłoby zdefiniowanie klasy statycznej Int64Converter<T> z właściwością statyczną bool Available {get;}; oraz statycznych delegatów dla Int64 GetInt64(T value), T FromInt64(Int64 value), bool TryStoreInt64(Int64 value, ref T dest). Konstruktor klasy może być zakodowany na twardo, aby załadować delegaty dla znanych typów i ewentualnie użyć Reflection, aby sprawdzić, czy type T implementuje metody z odpowiednimi nazwami i podpisami (w przypadku, gdy jest to coś w rodzaju struktury, która zawiera Int64 i reprezentuje liczbę, ale ma niestandardową metodę ToString()). Takie podejście straciłoby zalety związane z sprawdzaniem typu w czasie kompilacji, ale i tak uniknęłoby operacji bokserskich, a każdy typ musiałby być "sprawdzany" tylko raz. Następnie operacje związane z tym typem zostaną zastąpione wysyłaniem delegatów.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-06 15:44:04

Jeśli używasz. NET 4.0 i nowszych, możesz po prostu użyć dynamic jako argumentu metody i sprawdzić w runtime czy przekazany typ argumentu dynamic jest typem liczbowym/całkowitym.

Jeśli typ przekazanego dynamic jest typem , a nie numeric/integer, to wyrzuć wyjątek.

Przykład krótki Kod implementujący ten pomysł to coś w stylu:

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

Oczywiście, że to rozwiązanie działa tylko w czasie wykonywania, ale nigdy w kompilacji czas.

Jeśli chcesz mieć rozwiązanie, które zawsze działa w czasie kompilacji, a nigdy w czasie wykonywania, musisz zawinąć dynamic z publiczną klasą struct/, której przeciążone konstruktory public akceptują argumenty tylko pożądanych typów i nadają odpowiedniej nazwie struct/class.

Ma sens, że owinięty dynamiczny jest zawsze prywatnym członkiem klasy/struktury i jest jedynym członkiem struktury / klasy oraz nazwą jedynej elementem struktury / klasy jest "value".

Będziesz również musiał zdefiniować i zaimplementować public metody i/lub operatory, które działają z żądanymi typami dla prywatnego dynamicznego członka klasy/struktury, jeśli to konieczne.

Ma to również sens, że struktura / klasa ma specjalny/unikalny konstruktor , który przyjmuje dynamiczny jako argument inicjujący, że jest to tylko prywatny dynamiczny element o nazwie "value", ale modyfikator tego konstruktora jest Oczywiście.

Gdy Klasa / struct jest gotowa, zdefiniuj typ funkcji całkowitej argumentu jako tę klasę / struct, która została zdefiniowana.

Przykład długi Kod implementujący ten pomysł to coś w stylu:

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

Zauważ, że aby użyć dynamic w swoim kodzie musisz Dodać referencjędo Microsoft.CSharp

Jeśli wersja. NET framework jest poniżej / poniżej / poniżej 4.0 i dynamic jest undefined w tej wersji będziesz musiał użyć object zamiast object zamiast object zamiast 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-19 19:35:28

Nie ma jednego interfejsu ani klasy bazowej, które wszystkie dziedziczą (nie jest to również dziedziczone przez inne klasy), więc prosta odpowiedź brzmi nie.

Zastanawiam się jednak, dlaczego jest to problem. Co chcesz zrobić wewnątrz swojej klasy IntegerFunction, która może być zrobiona tylko dla liczb całkowitych?

 -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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-28 16:08:57

Myślę, że źle zrozumiałeś generyki. Jeśli operacja, którą próbujesz wykonać, jest dobra tylko dla określonych typów danych, to nie robisz czegoś "ogólnego".

Ponadto, ponieważ chcesz, aby funkcja działała tylko na typach danych int, nie powinieneś potrzebować osobnej funkcji dla każdego określonego rozmiaru. Po prostu biorąc parametr w największym określonym typie pozwoli programowi automatycznie upcast mniejszych typów danych do niego. (tj. przekazanie Int16 będzie Automatyczna konwersja na Int64 podczas wywołania).

Jeśli wykonujesz różne operacje na podstawie rzeczywistego rozmiaru int przekazywanego do funkcji, myślę, że powinieneś poważnie rozważyć nawet próbę zrobienia tego, co robisz. Jeśli musisz oszukać język, powinieneś pomyśleć trochę więcej o tym, co próbujesz osiągnąć, a nie jak robić to, co chcesz.

W przeciwnym razie można użyć parametru type Object i wtedy trzeba będzie sprawdzić typ parametr i podjąć odpowiednie działania lub rzucić wyjątek.

 -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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-28 16:36:36