Существует ли ограничение на С# для типов "реального числа"?
Возможный дубликат:
Общее ограничение С# для целых чисел
Поздравил!
Я пытаюсь настроить декартову систему координат в С#, но я не хочу ограничивать себя каким-либо одним числовым типом для моих значений координат. Иногда они могут быть целыми числами, а в других случаях они могут быть рациональными числами, в зависимости от контекста.
Это кричит "общий класс" для меня, но я в тупике о том, как сжимать тип как для интегралов, так и для плавающих точек. Я не могу найти класс, который охватывает любое понятие реальных чисел...
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 #