2009-08-12 2 views
43

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

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

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

UPDATE:

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

+1

Они не работают в этом сценарии, но когда вы работаете с Generics, хорошо знать «ограничения общего типа». http://msdn.microsoft.com/en-us/library/d5x73970%28VS.80%29.aspx – STW

+1

(ответил на комментарий) –

+1

Отметьте этот пост здесь http://stackoverflow.com/questions/32664/c- generic-constraint-for-only-integers – David

ответ

28

Какая версия .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 

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

T x = ..., T y = ... 
int c = Comparer<T>.Default.Compare(x,y); 
if(c < 0) { 
    // x < y 
} else if (c > 0) { 
    // x > y 
} 
+1

Я использую .NET 3.5, я пытался сделать «if (x> y)», а x и y типа T. –

+1

MiscUtil имеет Operator.GreaterThan, но вам это даже не нужно; обновится, чтобы показать, почему нет ... –

6

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

public class MyClass<T> where T : struct 
(...) 
+6

Почему не 'где Т: структура, IConvertible', это немного ближе. – BrainSlugs83

2

Я не верю, что вы можете определить это с помощью ограничения общего типа. Ваш код мог бы внутренне проверить ваши требования, возможно, используя Double.Parse или Double.TryParse, чтобы определить, является ли это число - , или если VB.NET не может быть и речи, вы можете использовать функцию IsNumeric().

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

8

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

Вы можете сортировать работу вокруг этого, определяя структуру без элементов, которая реализует интерфейс «Калькулятор». Мы использовали этот подход в родовом классе интерполяции в Pluto Toolkit. Для детального примера у нас есть «векторная» реализация калькулятора here, которая позволяет нашему родовому интерполятору работать с векторами. Существуют аналогичные для float, double, quaternions и т. Д.

+3

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

3

В Framework BCL (библиотека базового класса) многие числовые функции (такие как функции в 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); 
12

Есть интерфейсы для некоторых операций на числовых типах, как интерфейсы 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; }); 

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

2

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

класс YourClass <T> где T: IComparable, IFormattable, IConvertible, IComparabe <T>, IEquatable <T>, struct {... В конце концов вам все равно придется проверять во время выполнения, если ваш тип допустим с использованием метода object.GetType().

Если сравнивать только, то IComparable <T> только делает трюк.

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

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