首页 > 解决方案 > 以下数字赋值是否会导致 C# 中的隐式强制转换?

问题描述

这个问题主要是出于好奇,因为我在官方 C# 文档中找不到任何内容,而且性能成本可能完全可以忽略不计。

基本上,我想知道以下之间是否存在任何运行时成本差异:

float i = 0;

float i = 0.0f;

我会假设编译器足够聪明,可以在编译时转换00.0f直接分配它而无需强制转换。这个假设正确吗?

标签: c#performancecasting

解决方案


在您的代码示例中,两者之间没有什么不同。float无论最后是否有 f,您都已将类型声明为 a so,它将是一个浮点数。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 分配给浮点数,因为它是已知的。

所有泛型类型都有在编译时生成的元数据;因此编译器可以回答针对类型和标记错误的问题。然而,类型本身直到运行时才会生成;如果该类型是值类型或引用类型,则会更改它的生成方式。考虑这个签名:

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

请注意,在这里我不仅采用未知类型,而且将其分配给已知类型……然后将该类型完全更改为另一种类型,然后将其分配给另一种类型。编译器不在乎,一切正常......问题是如果我修改它以使事情不匹配,那么我会得到运行时异常而不是编译时间。根据您使用动态的方式,这可能是一个大问题。

希望这一切都有助于澄清一些事情。记住; 已知类型(编译时)、泛型(编译时元数据、运行时类型)和动态(运行时)。


推荐阅读