Как временно заменить один тип примитива другим при компиляции для разных целей? - PullRequest
5 голосов
/ 26 августа 2009

Как легко / быстро заменить числа с плавающей точкой для двойников (например) для компиляции двух разных целей, используя эти два конкретных типа примитивов?

Обсуждение: У меня есть большой объем кода на C #, который я разрабатываю, и который мне нужно скомпилировать для альтернативного использования чисел с плавающей запятой, двойных или десятичных чисел, в зависимости от варианта использования целевой сборки.

Использование чего-то вроде «class MYNumber: Double», так что необходимо изменить только одну строку кода, не работает, поскольку Double запечатан, и, очевидно, в C # нет #define. Перегрузка кода с помощью операторов #if #else также не возможна, слишком много поддержки Math-операторов / связанного кода с использованием этих конкретных примитивных типов.

Я в недоумении, как выполнить эту, казалось бы, простую задачу, спасибо!

Редактировать: просто быстрый комментарий относительно бокса, упомянутого в ответе Кайлса: К сожалению, мне нужно избегать бокса, в основном потому, что плавающие выбираются, когда требуется максимальная скорость, и десятичные, когда максимальная точность является приоритетом (и принимая 20x + хит производительности приемлемый). Бокс, вероятно, исключит десятичные дроби как правильный выбор и несколько победит цель.

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

Ответы [ 5 ]

8 голосов
/ 26 августа 2009

Лучший способ сделать это - использовать #if, как сказал Эндрю выше. Тем не менее, интересная идея для размышления будет примерно такой:

#if USE_FLOAT
using Numeric = System.Single;
#endif

#if USE_DOUBLE
using Numeric = System.Double;
#endif

#if USE_DECIMAL
using Numeric = System.Decimal;
#endif

public class SomeClass
{
    public Numeric MyValue{get;set;}
}

EDIT:

Мне все еще очень нравится это решение, оно позволяет вам делать некоторые действительно крутые вещи, такие как:

Numeric.Parse();
Numeric.TryParse();

, который будет работать для всех трех типов

0 голосов
/ 26 августа 2009

Это сложно, так как базовые типы не стимулируют что-то вроде IArithmetic. Это было предложено много раз на Connect . К сожалению, это хорошо известное ограничение дженериков .

Есть несколько обходных путей, использующих класс калькулятора структуры . Если математика не слишком обременительная, это делается, это работает очень, очень хорошо.

Однако, это неуклюже. Это единственное место, где дженерики не так гибки, как шаблоны C ++.

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

0 голосов
/ 26 августа 2009

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

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

0 голосов
/ 26 августа 2009

Вы можете сделать это:

public struct NumberContainer<T> 
{
    T _number;

    // accessor, and possibly: operators, cast methods, etc.
}

А потом:

#if USE_FLOAT
public struct MyNumber : NumberContainer<float>
#else
public struct MyNumber : NumberContainer<double>
#endif
{
}
0 голосов
/ 26 августа 2009

В худшем случае, я думаю, вы могли бы использовать бокс и что-то вроде этого:

#if USE_FLOAT
public float OutputValue(object input)
{
    return (float)input;
}
#endif

#if USE_DOUBLE
public double OutputValue(object input)
{
    return (double)input;
}
#endif

и позвоните по номеру OutputValue(1.5);, чтобы он преобразовал его для вас.

...