Вопрос по generics, c#, numbers – Дженерики - где Т это число? [Дубликат]
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.
что вы можете определить это, используя ограничение общего типа. Ваш код может внутренне проверить ваши требования, возможно, используя 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 #
например, функции в 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);
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);
}
}
}
}
то у меня естьреализация универсальных операторов в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
}
например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; });
Вы также можете хранить делегаты в классе и иметь разные фабричные методы, которые устанавливают делегатов для определенного типа данных. Таким образом, специфичный для типа код присутствует только в фабричных методах.
Но вы можете наложить больше ограничений, чтобы отсеять большинство «плохих типов»; на ваш числовой тип, как показано ниже
класс yourclass & lt; T & gt; где T: IComparable, IFormattable, IConvertible, IComparabe & lt; T & gt ;, IEquatable & lt; T & gt ;, struct {... В конце вы все равно должны будете проверить во время выполнения, является ли ваш тип приемлемым, используя метод object.GetType ().
Если только сравнение, то IComparable & lt; T & gt; один делает свое дело.
поскольку вам необходимо использовать один интерфейс для арифметических операций. В Connect было много запросов на добавление интерфейса IArithmetic для этой конкретной цели, но до сих пор все они были отклонены.
Вы можете обойти это, определив структуру без членов, которая реализует & quot; Калькулятор & quot; интерфейс. Мы взяли этот подход в универсальном классе интерполяции вПлутон Инструментарий, Для подробного примера у нас есть «вектор» реализация калькулятораВот, что позволяет нашему универсальному интерполятору работать с векторами. Есть аналогичные для поплавков, двойников, кватернионов и т. Д.