Приводит ли следующее числовое присвоение к неявному приведению в C #? - PullRequest
0 голосов
/ 16 октября 2018

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

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

float i = 0;

и

float i = 0.0f;

Я бы предположил, что компилятор достаточно умен, чтобы преобразовать 0 в 0.0f во время компиляции и напрямую назначить его без приведения.Это предположение верно?

Ответы [ 3 ]

0 голосов
/ 16 октября 2018

В вашем примере кода нет ничего отличного между этими двумя.Вы объявили тип как float, так что независимо от того, будет ли f в конце или нет, это будет float.F просто игнорируется.

f вступает в игру при выполнении уравнений или назначении общих переменных, таких как использование ключевого слова var.

Например:

var value = 0; // this is assigned as integer.

var value = 0.0f // this is assigned as float.

var value = 0.0; // this is assigned as double.

А вот пример расчета:

Примечание: Для пониманияПолные числа с плавающей запятой - это совершенно другой урок, но знание того, что вычисления выполняются по-разному в зависимости от типа, такого как целое число, число с плавающей запятой (f), двойное число (d) или десятичное число (m), в основном имеет значение .

Обратите внимание, что математика отличается от типа к типу.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(1 / 3);
        Console.WriteLine(1f / 3);
        Console.WriteLine(1d / 3);
        Console.WriteLine(1m / 3);

        Console.ReadKey();
    }
    // OUTPUT
    // 0
    // 0.3333333
    // 0.333333333333333
    // 0.3333333333333333333333333333
}

Также обратите внимание, что когда вы устанавливаете тип в вычислении, ТОЛЬКО та часть вычисления получает результат этого типа.Рассмотрите этот пример смешанных типов в вычислениях:

class Program
{
    static void Main(string[] args)
    {
        //float + integer
        Console.WriteLine(1f / 3 + 1 / 3);

        //double + integer
        Console.WriteLine(1d / 3 + 1 / 3);

        //double + float
        Console.WriteLine(1d / 3 + 1 / 3f);

        //decimal + integer
        Console.WriteLine(1m / 3 + 1 / 3);

        //decimal + decimal
        Console.WriteLine(1m / 3 + 1 / 3m);

        Console.ReadKey();
    }
    // OUTPUT
    // 0.3333333
    // 0.333333333333333
    // 0.666666676600774
    // 0.3333333333333333333333333333
    // 0.6666666666666666666666666666
}

Обновлен, чтобы включать информацию, основанную на комментариях ниже

Чтобы обновить мой ответ на основе комментария нижеи компиляция и генерация объектов во время выполнения.

Все известные типы генерируются во время компиляции.Итак, в вашем вопросе, да, компилятор назначит 0 для float, поскольку он известен.

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

public void MyMethod<T>(T myType)

Поскольку этот метод является универсальным, новый создается для каждого отдельного типа значения во время выполнения, только когда этот тип используется, и только один раз затип значения (одни и те же типы значений используют один и тот же сгенерированный тип).Посмотрите на приведенный ниже код.

MyMethod(12);           // new type method built at runtime taking integer
MyMethod(12d);          // new type method built at runtime taking double
MyMethod(12);           // ** resuses already built type method taking integer
MyMethod(new Person()); // new type method built at runtime taking Person
MyMethod(new object()); // ** resuses type method built taking Person but uses object pointer.

Итак, вы можете видеть, что компилятор может помочь нам разрешить конфликты типов, но тип, который использует универсальные типы, не существует до времени выполнения;и важно знать, когда они существуют и как они используются между значениями и ссылочными типами.

Наконец, у нас есть dynamic.Это никогда не разрешается во время компиляции и фактически игнорируется до времени выполнения.Вы можете делать все, что вы хотите здесь;это немного похоже на написание JavaScript;этот маленький мятежный дьявол.Рассмотрим этот код:

static void Main(string[] args)
{
    dynamic value = 1;
    Console.WriteLine(value);

    int integer = value;
    Console.WriteLine(integer);

    value = "Hello World";
    Console.WriteLine(value);

    string text = value;
    Console.WriteLine(text);

    Console.ReadKey();
}
// OUTPUT
// 1
// 1
// Hello World
// Hello World

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

Надеюсь, все это поможет немного прояснить ситуацию.Помните;известные типы (время компиляции), обобщенные (метаданные времени компиляции, типы времени выполнения) и динамические (время выполнения).

0 голосов
/ 16 октября 2018
  float i = 0; // 'conversion' can be done at compile-time

Формально существует неявное преобразование из int в float.Но когда рассматриваемый int является константой времени компиляции, как в данном случае литералом 0, преобразование выполняется компилятором C #.

Так что обе ваши строки дают одну и ту же программу (тот же IL).

Однако в этом случае:

static void M1(int n)
{
  float i = n; // actual conversion at run-time
  Console.WriteLine(i);
}

static void M2(float f)
{
  float i = f; // same types
  Console.WriteLine(i);
}

может быть разница, поскольку M1 необходимо преобразовать из int (Int32) в float (Single), тогда как M2 не нуждается в преобразовании.

0 голосов
/ 16 октября 2018

Разницы нет, см. Декомпилированный через csharp labs Код IL:

Код C #:

using System;
// Run mode:
//   value.Inspect()      — often better than Console.WriteLine
//   Inspect.Heap(object) — structure of an object in memory (heap)
//   Inspect.Stack(value) — structure of a stack value
public static class Program {
    public static void Main() {
        float i = 0;
        float i2 = 0.0f;

    }
}

Код IL:

.class private auto ansi '<Module>'
{
} // end of class <Module>

.class public auto ansi abstract sealed beforefieldinit Program
    extends [mscorlib]System.Object
{
    // Methods
    .method public hidebysig static 
        void Main () cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 14 (0xe)
        .maxstack 1
        .locals init (
            [0] float32,
            [1] float32
        )

        IL_0000: nop
        IL_0001: ldc.r4 0.0
        IL_0006: stloc.0
        IL_0007: ldc.r4 0.0
        IL_000c: stloc.1
        IL_000d: ret
    } // end of method Program::Main

} // end of class Program
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...