冗余代码是在编译器中管理还是每次都执行?

时间:2019-07-17 12:01:26

标签: c# asp.net asp.net-core

我正在优化旧代码(并将一些代码转移到新项目中),但偶然发现了这段代码

if (typeList.FirstOrDefault()?.typeId == Constants.OpenTextTypeId)
    generatedTextStrBuilder.Append("Empty");
else if (typeList.FirstOrDefault()?.typeId == Constants.OutSideId)
    generatedTextStrBuilder.Append($" [{ typeList.First().typeName }] ");
else if (Constants.typeListOfReview.Contains(typeList.FirstOrDefault()?.typeId))
    generatedTextStrBuilder.Append($"*[{ typeList.FirstOrDefault()?.typeName }]*");
else
    generatedTextStrBuilder.Append($"_[{ typeList.FirstOrDefault()?.typeName }]_");
正如您在代码中看到的

typeList.FirstOrDefault()?.typeId在每种情况下都写入一次

问题是:编译器是管理这种类型的冗余还是每次执行?

如果编译器这样做,它是否仅在此方法内对其进行管理?

3 个答案:

答案 0 :(得分:2)

编译器必须发出每次调用function uploadXML(){ let xml = '<thexml_you_got_from_the_export><thexml_you_got_from_the_export/>'; let doc = mxUtils.parseXml(xml); let codec = new mxCodec(doc); codec.decode(doc.documentElement, universalGraph.getModel()); let elt = doc.documentElement.firstChild; let cells = []; while (elt != null) { let cell = codec.decode(elt) if(cell != undefined){ if(cell.id != undefined && cell.parent != undefined && (cell.id == cell.parent)){ elt = elt.nextSibling; continue; } cells.push(cell); } elt = elt.nextSibling; } universalGraph.addCells(cells); } 的代码。毕竟,以下任何一项都可能成立:

  • FirstOrDefault()所引用的对象可能在typeListif之间变化,例如在多线程应用程序中。
  • else if的输出可能取决于某些外部状态,而不仅取决于输入,因此多个调用可能返回不同的结果。
  • FirstOrDefault可能会有副作用。

如果考虑到这一点,编译器删除“冗余”代码的唯一方法是if

  • FirstOrDefault是不可变对象的不可变集合,每次都会以相同的顺序返回项目。
  • typeList是一个纯函数,即它仅取决于输入并且没有副作用,并且
  • 如果基础对象未更改,
  • FirstOrDefault将返回相同的值。

(此条件列表很可能不完整,并且可能比此简单列表所暗示的要复杂得多)

答案 1 :(得分:1)

我不希望编译器缓存结果-FirstOrDefault是确定性的,除非底层列表在检查分支条件之间发生变化,但这当然不是编译器所了解的。您可能已经很容易在IEnumerable上调用了扩展方法,该方法每次都返回一个随机项而不是第一个项。您可以通过创建自己的扩展方法(类似于以下内容)轻松验证这一点...

public static class MyEnumerableExtensions
    {
        public static T MyFirstOrDefault<T>(this IEnumerable<T> enumerable)
        {
            Console.WriteLine("Executing FirstOrDefault()");
            return enumerable.FirstOrDefault();
        }
    }



public class Program
{


    public class Type
    {
        public int TypeId { get; set; }
    }

    public static void Main(string[] args)
    {
        var typeList = new List<Type>
        {
            new Type { TypeId = 4 }
        };

        if (typeList.MyFirstOrDefault().TypeId == 1)
        {
            Console.WriteLine("1");
        }
        else if (typeList.MyFirstOrDefault().TypeId == 2)
        {
            Console.WriteLine("2");
        }
        else if (typeList.MyFirstOrDefault().TypeId == 3)
        {
            Console.WriteLine("3");
        }
        else
        {
            Console.WriteLine("other");
        }
    }
}

控制台输出为

Executing FirstOrDefault()
Executing FirstOrDefault()
Executing FirstOrDefault()
other

我当然会提取将typeId返回到变量中的表达式-这也有利于提高可读性。

答案 2 :(得分:0)

是的。因为

,它将每次执行

例如,当我构建一个小项目(RELEASE构建)时

int i = 0;
Console.WriteL("Hello world !")

编译并生成exe文件

然后我通过 .Net Reflection 对其进行了反编译,并且我发现在已编译的代码中仍然存在冗余行(int i = 0)。