Приведение моего класса к Int64, Double и т. Д. - PullRequest
6 голосов
/ 29 февраля 2012

Смежный вопрос: Доступ к свойству класса без использования оператора точки

Я создал класс с именем MyDouble, выглядит так

class MyDouble
{
  double value;
  //overloaded operators and methods
}

Я могу выполнять любые операции с MyDouble. Примеры:

MyDouble a = 5.0;
a += 3.0;
...etc

Однако, это все равно выдает ошибку

MyDouble a = 5.0;
long b = (Int64)a;  //error
long b = (int64)a.value; //works

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

Ответы [ 3 ]

9 голосов
/ 29 февраля 2012

Чтобы это преобразование работало, вам потребуется явное преобразование в Int64.

Это будет выглядеть так:

class MyDouble
{
    double value;

    public static explicit operator Int64(MyDouble value)
    {
         return (Int64)value.value;
    }
}
1 голос
/ 29 февраля 2012

Неявное преобразование будет работать так же, как и явное преобразование.

public static implicit operator long(MyDouble m)
{
    return (long) m.value;
}

С этим вы можете сделать:

long b = (Int64) a;

или просто

long b = a;

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

1 голос
/ 29 февраля 2012

Существует явное преобразование из double в Int64, но не из вашего класса в Int64.все, что вам нужно сделать, это определить один.Или, если у вас есть преобразование из вашего класса в удвоение, что, как я полагаю, у вас, вы можете сделать так:

long x = (long) (double) a;

Однако этогромоздким;Я бы определил оператор явного преобразования.

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

Преобразование, определяемое языком, от двойного к длинномуявляется явным , потому что преобразование может привести к потере информации. Вы можете потерять информацию при таком преобразовании, потому что есть некоторые двойные числа, такие как 0,5, , которые не преобразуются точно в длинную. Это называется сужающее преобразование .

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

Вот пример, демонстрирующий ценность этого принципа.Если бы сужающие преобразования были неявными, это сделало бы код более хрупким.Предположим, что преобразование типа double в int является неявным:

class Family
{
    ICollection<Person> Children { get; set; }
}

int GetAverageNumberOfChildren(IEnumerable<Family> families)
{
    return families.Sum(f => f.Children.Count) / families.Count();
}

void SomeMethod(IEnumerable<Family> families)
{
    int averageNumberOfChildren = GetAverageNumberOfChildren(families);
    //...
}

Упс!У нас есть ошибка!GetAverageNumberOfChildren должен вернуть двойной!Давайте это исправим!

double GetAverageNumberOfChildren(IEnumerable<Family> families)
{
    return families.Average(f => f.Children.Count);
}

Вот так, все компилируется и запускается!Конечно, рад, что мы поймали эту ошибку!

Но, к сожалению, нет. У нас все еще есть ошибка! SomeMethod неявно преобразует double в целое, поэтому, где ожидаемое значение может быть 2.4, действительное значение равно 2.

Поскольку doubleпреобразование -to-int явно , компилятор спасает нас от нас самих.После того, как мы исправим GetAverageNumberOfChildren, , ошибочная программа не компилируется.

Теперь, если ваш класс MyDouble имел некоторую проверку, которая ограничивала его целочисленными значениями с диапазоном, равным или меньшимчем диапазон long, тогда вы могли бы сделать преобразование неявным.Но в этом случае, конечно, вы должны использовать long, а не double.

...