Вопрос по generics, c#, numbers – Дженерики - где Т это число? [Дубликат]

50

This question already has an answer here:

Is there a constraint that restricts my generic method to numeric types? 20 answers

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

Существует ли общий интерфейс для всех типов чисел (int, double, float ...), которые мне не хватает ???

Если нет, что будет лучшим способом создать такой класс?

UPDATE:

Главное, чего я пытаюсь достичь, - это проверить, кто больше между двумя переменными типа T.

Проверьте этот пост здесьstackoverflow.com/questions/32664/… David
Они не работают в этом сценарии, но когда вы работаете с Generics, полезно знать о «ограничениях универсального типа».msdn.microsoft.com/en-us/library/d5x73970%28VS.80%29.aspx STW
Насколько я знаю, это невозможно.You may find some reasons why (and alternative solutions) here. Fredrik Mörk
Вы пробовали IConvertible / IComparible? - Все классы чисел поддерживают это. BrainSlugs83
(ответил на комментарий) Marc Gravell♦

Ваш Ответ

8   ответов
2

что вы можете определить это, используя ограничение общего типа. Ваш код может внутренне проверить ваши требования, возможно, используя Double.Parse или Double.TryParse, чтобы определить, является ли это число:or if VB.NET isn't out of the question then you could use the IsNumeric() function.

Edit: Вы можете добавить ссылку на Microsoft.VisualBasic.dll и вызвать функцию IsNumeric () из c #

4

например, функции в System.Math) справляются с этим, имея перегрузки для каждого числового типа.

Статический класс Math в BCL содержит статические методы, которые можно вызывать, не создавая экземпляр класса. Вы могли бы сделать то же самое в своем классе. Например, Math.Max имеет 11 перегрузок:

public static byte Max(byte val1, byte val2);
public static decimal Max(decimal val1, decimal val2);
public static double Max(double val1, double val2);
public static short Max(short val1, short val2);
public static int Max(int val1, int val2);
public static long Max(long val1, long val2);
public static sbyte Max(sbyte val1, sbyte val2);
public static float Max(float val1, float val2);
public static ushort Max(ushort val1, ushort val2);
public static uint Max(uint val1, uint val2);
public static ulong Max(ulong val1, ulong val2);
3
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GenericPratice1
{
    public delegate T Del<T>(T numone, T numtwo)where T:struct;
    class Class1
    {
        public T Addition<T>(T numone, T numtwo) where T:struct
        {
            return ((dynamic)numone + (dynamic)numtwo);
        }
        public T Substraction<T>(T numone, T numtwo) where T : struct
        {
            return ((dynamic)numone - (dynamic)numtwo);
        }
        public T Division<T>(T numone, T numtwo) where T : struct
        {
            return ((dynamic)numone / (dynamic)numtwo);
        }
        public T Multiplication<T>(T numone, T numtwo) where T : struct
        {
            return ((dynamic)numone * (dynamic)numtwo);
        }

        public Del<T> GetMethodInt<T>(int ch)  where T:struct
        {
            Console.WriteLine("Enter the NumberOne::");
            T numone =(T) Convert.ChangeType((object)(Console.ReadLine()), typeof(T));
            Console.WriteLine("Enter the NumberTwo::");
            T numtwo = (T)Convert.ChangeType((object)(Console.ReadLine()), typeof(T));
            T result = default(T);
            Class1 c = this;
            Del<T> deleg = null;
            switch (ch)
            {
                case 1:
                    deleg = c.Addition<T>;
                    result = deleg.Invoke(numone, numtwo);
                    break;
                case 2: deleg = c.Substraction<T>;
                    result = deleg.Invoke(numone, numtwo);
                    break;
                case 3: deleg = c.Division<T>;
                    result = deleg.Invoke(numone, numtwo);
                    break;
                case 4: deleg = c.Multiplication<T>;
                    result = deleg.Invoke(numone, numtwo);
                    break;
                default:
                    Console.WriteLine("Invalid entry");
                    break;
            }
            Console.WriteLine("Result is:: " + result);
            return deleg;
        }

    }
    class Calculator
    {
        public static void Main(string[] args)
        {
            Class1 cs = new Class1();
            Console.WriteLine("Enter the DataType choice:");
            Console.WriteLine("1 : Int\n2 : Float");
            int sel = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine("Enter the choice::");
            Console.WriteLine("1 : Addition\n2 : Substraction\3 : Division\4 : Multiplication");
            int ch = Convert.ToInt32(Console.ReadLine());
            if (sel == 1)
            {
                cs.GetMethodInt<int>(ch);
            }
            else
            {
                cs.GetMethodInt<float>(ch);
            }

        }
    }
}
29

то у меня естьреализация универсальных операторов вMiscUtil (бесплатно и т. д.).

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

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

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

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

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

Re комментарий о< / > - вы на самом деле неneed операторы для этого; вам просто нужно:

T x = ..., T y = ...
int c = Comparer<T>.Default.Compare(x,y);
if(c < 0) {
    // x < y
} else if (c > 0) { 
    // x > y
}
MiscUtil имеет Operator.GreaterThan, но вам это даже не нужно; будет обновляться, чтобы показать, почему нет ...
Я использую .NET 3.5, я пытался сделать "if (x & gt; y)" в то время как х и у типа Т. CD..
15

напримерIComparable<T>, IConvertible а такжеIEquatable<T> интерфейсы. Вы можете указать это, чтобы получить определенную функциональность:

public class MaxFinder<T> where T : IComparable<T> {

   public T FindMax(IEnumerable<T> items) {
      T result = default(T);
      bool first = true;
      foreach (T item in items) {
         if (first) {
            result = item;
            first = false;
         } else {
            if (item.CompareTo(result) > 0) {
               result = item;
            }
         }
      }
      return result;
   }

}

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

public class Adder<T> {

   public delegate T AddDelegate(T item1, T item2);

   public T AddAll(IEnumerable<T> items, AddDelegate add) {
      T result = default(T);
      foreach (T item in items) {
         result = add(result, item);
      }
      return result;
   }

}

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

Adder<int> adder = new Adder<int>();
int[] list = { 1, 2, 3 };
int sum = adder.AddAll(list, delegate(int x, int y) { return x + y; });

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

8

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

public class MyClass<T> where T : struct
(...)
почему бы и нетwhere T: struct, IConvertibleЭто, по крайней мере, немного ближе.
2

Но вы можете наложить больше ограничений, чтобы отсеять большинство «плохих типов»; на ваш числовой тип, как показано ниже

класс yourclass & lt; T & gt; где T: IComparable, IFormattable, IConvertible, IComparabe & lt; T & gt ;, IEquatable & lt; T & gt ;, struct {... В конце вы все равно должны будете проверить во время выполнения, является ли ваш тип приемлемым, используя метод object.GetType ().

Если только сравнение, то IComparable & lt; T & gt; один делает свое дело.

8

поскольку вам необходимо использовать один интерфейс для арифметических операций. В Connect было много запросов на добавление интерфейса IArithmetic для этой конкретной цели, но до сих пор все они были отклонены.

Вы можете обойти это, определив структуру без членов, которая реализует & quot; Калькулятор & quot; интерфейс. Мы взяли этот подход в универсальном классе интерполяции вПлутон Инструментарий, Для подробного примера у нас есть «вектор» реализация калькулятораВот, что позволяет нашему универсальному интерполятору работать с векторами. Есть аналогичные для поплавков, двойников, кватернионов и т. Д.

это неработающая ссылка!

Похожие вопросы