0Pricing
C# Academy · Урок

Пользовательские преобразования

Добавляйте операторы неявного и явного преобразования.

«Пользовательские преобразования» — бесплатный урок C# Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Преобразования, определённые пользователем

C# позволяет типу определять преобразование в другой тип или из него с помощью операторов implicit и explicit. Неявные преобразования выполняются автоматически, а для явных требуется приведение типа.

Неявное преобразование

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

using System;

public struct Celsius
{
    public double Degrees;
    public Celsius(double d) { Degrees = d; }

    // Always safe: a Celsius is just a number
    public static implicit operator double(Celsius c) => c.Degrees;
}

public class Program
{
    public static void Main()
    {
        Celsius temp = new Celsius(21.5);
        double d = temp; // implicit, no cast needed
        Console.WriteLine(d);
    }
}

Явное преобразование

Используйте explicit operator, если преобразование может привести к потере данных или завершиться ошибкой. Вызывающий код должен явно записать приведение типа, показывая, что риск принят.

using System;

public struct Money
{
    public decimal Amount;
    public Money(decimal a) { Amount = a; }

    // Loses the fractional cents, so make it explicit
    public static explicit operator int(Money m) => (int)m.Amount;
}

public class Program
{
    public static void Main()
    {
        var m = new Money(19.99m);
        int dollars = (int)m; // explicit cast required
        Console.WriteLine(dollars);
    }
}

Преобразование в Ваш тип

Преобразование может выполняться и в обратную сторону: из другого типа в Ваш. Здесь оператор implicit создаёт Celsius из исходного значения типа double.

using System;

public struct Celsius
{
    public double Degrees;
    public Celsius(double d) { Degrees = d; }

    public static implicit operator Celsius(double d) => new Celsius(d);

    public override string ToString() => Degrees + "C";
}

public class Program
{
    public static void Main()
    {
        Celsius t = 18.0; // double implicitly becomes Celsius
        Console.WriteLine(t);
    }
}

Неявные или явные преобразования: что выбрать

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

using System;

public struct Percentage
{
    public double Value; // 0..1
    public Percentage(double v) { Value = v; }

    // Safe and lossless -> implicit
    public static implicit operator double(Percentage p) => p.Value;
    // Could be out of range -> explicit
    public static explicit operator Percentage(double v) => new Percentage(v);
}

public class Program
{
    public static void Main()
    {
        double d = new Percentage(0.25);
        var p = (Percentage)0.5;
        Console.WriteLine(d + " " + p.Value);
    }
}

Преобразования между пользовательскими типами

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

using System;

public struct Cartesian
{
    public double X, Y;
    public Cartesian(double x, double y) { X = x; Y = y; }
    public override string ToString() => "(" + Math.Round(X, 2) + ", " + Math.Round(Y, 2) + ")";
}

public struct Polar
{
    public double R, Theta;
    public Polar(double r, double theta) { R = r; Theta = theta; }
    public static explicit operator Cartesian(Polar p)
        => new Cartesian(p.R * Math.Cos(p.Theta), p.R * Math.Sin(p.Theta));
}

public class Program
{
    public static void Main()
    {
        var c = (Cartesian)new Polar(1.0, 0.0);
        Console.WriteLine(c);
    }
}

Преобразования сочетаются с операторами

После появления преобразования значение участвует в выражениях целевого типа. Неявное преобразование в double позволяет напрямую использовать ваш тип в арифметических операциях.

using System;

public struct Meters
{
    public double Value;
    public Meters(double v) { Value = v; }
    public static implicit operator double(Meters m) => m.Value;
}

public class Program
{
    public static void Main()
    {
        var distance = new Meters(5);
        double doubled = distance * 2; // uses implicit conversion to double
        Console.WriteLine(doubled);
    }
}

Избегайте неожиданных неявных преобразований

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

using System;

public struct UserId
{
    public int Value;
    public UserId(int v) { Value = v; }
    // Explicit on purpose: an int is not always a valid id
    public static explicit operator UserId(int v) => new UserId(v);
    public static explicit operator int(UserId id) => id.Value;
}

public class Program
{
    public static void Main()
    {
        var id = (UserId)42;
        int raw = (int)id;
        Console.WriteLine(raw);
    }
}

Операторы преобразования являются статическими

Как и другие операторы, операторы преобразования имеют модификаторы public static. Ровно один из участвующих типов должен быть типом, объявляющим этот оператор.

using System;

public struct Fahrenheit
{
    public double Degrees;
    public Fahrenheit(double d) { Degrees = d; }
    public static implicit operator Fahrenheit(double d) => new Fahrenheit(d);
    public static implicit operator double(Fahrenheit f) => f.Degrees;
    public override string ToString() => Degrees + "F";
}

public class Program
{
    public static void Main()
    {
        Fahrenheit f = 98.6;
        double d = f;
        Console.WriteLine(f + " = " + d);
    }
}

Практический тип-обёртка

Преобразования особенно полезны для простых типов-обёрток, которые усиливают систему типов без лишних сложностей. Здесь NonEmptyString неявно преобразуется в string, но для его создания требуется явное приведение.

using System;

public struct NonEmptyString
{
    public string Value;
    public NonEmptyString(string v)
    {
        if (string.IsNullOrEmpty(v)) throw new ArgumentException("empty");
        Value = v;
    }
    public static explicit operator NonEmptyString(string s) => new NonEmptyString(s);
    public static implicit operator string(NonEmptyString s) => s.Value;
}

public class Program
{
    public static void Main()
    {
        var name = (NonEmptyString)"Ada";
        string s = name;
        Console.WriteLine(s);
    }
}

Попробуйте сами

Определите тип-обёртку с безопасным неявным преобразованием из него и проверяемым явным преобразованием в него. Обратите внимание, в каком направлении требуется приведение.

using System;

public struct Ratio
{
    public double Value;
    public Ratio(double v)
    {
        if (v < 0 || v > 1) throw new ArgumentOutOfRangeException(nameof(v));
        Value = v;
    }
    public static implicit operator double(Ratio r) => r.Value; // always safe
    public static explicit operator Ratio(double v) => new Ratio(v); // may throw
}

public class Program
{
    public static void Main()
    {
        var half = (Ratio)0.5;   // explicit, validated
        double d = half;          // implicit, safe
        Console.WriteLine(d * 100 + "%");
    }
}

Быстрая проверка

Выберите подходящий вид преобразования.

Итоги

Пользовательские преобразования позволяют вашим типам удобно взаимодействовать.

  • implicit operator — для всегда безопасных преобразований без потери данных.
  • explicit operator — когда возможна потеря данных или преобразование может завершиться ошибкой.
  • Преобразования могут выполняться между встроенными или пользовательскими типами в любом направлении.
  • Они имеют модификаторы public static и объявляются одним из участвующих типов.

Часто задаваемые вопросы

Урок «Пользовательские преобразования» бесплатный?

Да — полный текст урока «Пользовательские преобразования» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Пользовательские преобразования»?

Добавляйте операторы неявного и явного преобразования. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Пользовательские преобразования»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Перегрузка арифметических операторов
  2. Перегрузка операторов сравнения
  3. Пользовательские преобразования
  4. Рекомендации по перегрузке операторов
← Назад к C# Academy