Существует ли ограничение на С# для типов "реального числа"?

Возможный дубликат:
Общее ограничение С# для целых чисел

Поздравил!

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

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

public class Point<T> where T : [SomeClassThatIncludesBothIntsandFloats?]  {
    T myX, myY;

    public Point(T x, T y) {
        myX = x;
        myY = y;
    }
}

Point<int> pInt = new Point<int>(5, -10);
Point<float> pFloat = new Point<float>(3.14159, -0.2357);

Если я хочу этот уровень свободы, я выбираю кошмар типа "typeof (T)", когда дело доходит до вычислений внутри моих классов, отсеивая bools, строки, объекты и т.д.? Или, что еще хуже, я выбираю сделать класс для каждого типа числа, с которым хочу работать, каждый с теми же внутренними математическими формулами?

Любая помощь будет оценена по достоинству. Спасибо!

Ответ 1

Вы не можете определить такое ограничение, но вы можете проверить тип во время выполнения. Это не поможет вам делать расчеты.

Если вы хотите выполнять вычисления, то это будет вариант:

class Calculations<T, S> where S: Calculator<T>, new()
{
    Calculator<T> _calculator = new S();

    public T Square(T a)
    {
        return _calculator.Multiply(a, a);
    }

}

abstract class Calculator<T>
{
    public abstract T Multiply(T a, T b);
}

class IntCalculator : Calculator<int>
{
    public override int Multiply(int a, int b)
    {
        return a * b;
    }
}

Аналогичным образом определите a FloatCalculator и любые операции, которые вам нужны. Это не особенно быстро, хотя быстрее, чем конструкция С# 4.0 dynamic.

var calc = new Calculations<int, IntCalculator>();
var result = calc.Square(10);

Побочным эффектом является то, что вы сможете создавать экземпляры Calculator только в том случае, если тип, который вы передаете ему, имеет соответствующую реализацию Calculator<T>, поэтому вам не нужно проверять тип выполнения.

Это в основном то, о чем Хейлсберг упоминал в этом интервью, где обсуждался этот вопрос. Лично мне бы хотелось увидеть какой-то базовый тип:)

Ответ 2

Это очень распространенный вопрос; если вы используете .NET 3.5, для этой поддержки в MiscUtil существует поддержка Operator, который поддерживает встроенные типы и любые пользовательские типы с операторами (включая" снятые" операторы); в частности, это позволяет использовать с дженериками, например:

public static T Sum<T>(this IEnumerable<T> source) {
    T sum = Operator<T>.Zero;
    foreach (T value in source) {
        if (value != null) {
            sum = Operator.Add(sum, value);
        }
    }
    return sum;
}

Или для другого примера; Complex<T>

Ответ 3

Это известная проблема, так как ни один из арифметических классов не приходит из одного класса. Поэтому вы не можете его ограничивать.

Единственное, что вы можете сделать, это

where T : struct

но это не совсем то, что вы хотите.

Вот ссылка на конкретную проблему.

Арифметические типы, такие как int, double, decimal, должны реализовывать IArithmetic <T>

Ответ 4

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

Создайте две структуры, называемые say MyInt и MyDecimal, которые действуют как фасады для CTS Int32 и десятичных типов ядра (они содержат внутреннее поле соответствующего типа.) Каждый из них должен иметь ctor, который принимает экземпляр Тип Core CTS в качестве входного параметра.

Сделайте каждый из них реализацией пустого интерфейса с именем INumeric

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

ПРИМЕЧАНИЕ. Кодирование пользовательских структур для правильного эмуляции всех типов основных типов CTS - утомительная часть... Вам необходимо реализовать несколько встроенных интерфейсов CLR (IComparable и т.д.) и перегрузить всю арифметику и логические операторы...

Ответ 5

Вы можете приблизиться к реализации еще нескольких

public class Point<T> where T : struct, IComparable, IFormattable, IConvertible, 
                                IComparable<T>, IEquatable<T> {   
}

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

Ответ 6

Thi может быть вам полезна. Вы должны использовать общий класс для достижения желаемого.

Ответ 7

В настоящее время С# не допускает ограничений типа для типов значений. Я задал близкий вопрос не так давно.

Ограничения типа Enum в С#

Ответ 8

Не будет ли это иметь отдельные классы, реализующие IPoint?

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

public interface IPoint<T>  
{
    T X { get; set; }
    T Y { get; set; }
}

public class IntegerPoint : IPoint<int>
{

    public int X { get; set; }
    public int Y { get; set; }
}

Так как вычисления будут по-разному отличаться в каждой реализации?

Dan #