ОБЩИЙ C # способ округлить число до ближайшего кратного?(Не дубликат, имеет определенный угол и предложенный ответ) - PullRequest
0 голосов
/ 07 февраля 2019

У меня есть метод расширения C # следующим образом:

public static double RoundOff(this double rawNumber, double roundToNearest)
{
    double rawMultiples     = rawNumber / roundToNearest;
    double roundedMultiples = Math.Round(rawMultiples);
    double roundedNumber    = roundedMultiples * roundToNearest;
    return roundedNumber;
}

Я не хочу писать его несколько раз для всех различных числовых типов (целых, десятичных и т. Д.)

Есть ли способ сделать это в общем, как это?

public static double RoundOff<T>(this T rawNumber, T roundToNearest)
    where T : [SOME CONSTRAINT]
{
    T rawMultiples     = rawNumber / roundToNearest;
    T roundedMultiples = Math.Round(rawMultiples);
    T roundedNumber    = roundedMultiples * roundToNearest;
    return roundedNumber;
}

Было бы так полезно иметь возможность сделать это в более общем плане.Меньше кода для поддержки - и больше возможностей только от одного метода расширения!

Если это невозможно, не потому ли, что C # не может быть расширен для такой работы?Или это может быть когда-нибудь продлено, чтобы разрешить общее ограничение «все числовые типы»?

Любые идеи приветствуются.

ОБНОВЛЕНИЕ В ответ на вопрос осходство с другим вопросом.Да, это похоже на предмет, но отличается, потому что я после конкретного решения конкретной проблемы.Я добавил свой собственный ответ ниже, чтобы уточнить.Задачи приветствуются, если кто-то все еще думает, что я упустил момент

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

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

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

    public static T RoundOff<T>(this T rawNumber, T roundToNearest)
        where T : IComparable<T>
    {
        if (typeof(T).IsNumericType())
        {
            decimal decimalRoundToNearest   = Convert.ToDecimal(roundToNearest);
            decimal rawMultiples            = Convert.ToDecimal(rawNumber) / Convert.ToDecimal(roundToNearest);
            decimal decimalRoundedMultiples = Math.Round(rawMultiples);
            decimal decimalRoundedNumber    = decimalRoundedMultiples * decimalRoundToNearest;

            return (T)Convert.ChangeType(decimalRoundedNumber, typeof(T));
            // alternative
            // TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
            // return (T)converter.ConvertFrom(decimalRoundedNumber);

        }
        else
        {
            throw new Exception("Type " + typeof(T) + " is not numeric");
        }
    }

И этот метод расширения с логикой заимствован из цитируемого ответа

    public static bool IsNumericType(this object o)
    {
        // /1281215/c-kak-opredelit-yavlyaetsya-li-tip-chislom
        switch (Type.GetTypeCode(o.GetType()))
        {
            case TypeCode.Byte:
            case TypeCode.SByte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
            case TypeCode.Decimal:
            case TypeCode.Double:
            case TypeCode.Single:
                return true;

            default:
                return false;
        }
    }

Не без его слабостей, но он делает то, что мне нужно.

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

Так что я надеюсь, что это или кому-то поможет, или спровоцирует лавину гневных ответов о том, как это можно сделать лучше !!

0 голосов
/ 07 февраля 2019

Очевидно, что с Generics невозможно сделать именно то, что вы хотите, как говорят другие комментаторы, но, поскольку все числа могут быть преобразованы в двойные, вы можете по крайней мере уменьшить дублирование логики:

public static double RoundOff(this long rawNumber, double roundToNearest)
{
    return RoundOff((double) rawNumber, roundToNearest);
}

public static double RoundOff(this double rawNumber, double roundToNearest)
{
    T rawMultiples     = rawNumber / roundToNearest;
    T roundedMultiples = Math.Round(rawMultiples);
    T roundedNumber    = roundedMultiples * roundToNearest;
    return roundedNumber;
}

Есливы обходитесь без метода расширения, тогда вы можете просто вызывать этот метод напрямую для любых чисел, поскольку C # просто автоматически преобразует все типы в удвоенные значения

int i = 5;
RoundOff(i, 0.5);
...