Does conditional compilation optimise away methods that generate input arguments? - c#

In C#, we can perform conditional compilation using #if / #endif statements or with Conditional attributes. For example, the following code will print something only for a debug build:
public static void Main(string[] args)
{
CheckResult();
}
[Conditional("DEBUG")]
private static void CheckResult()
{
System.Console.WriteLine("everything is fine");
}
What happens, though, if this CheckResult() method accepts arguments, and we use it like so?
public static void Main(string[] args)
{
CheckResult(CalculateSomethingExpensive() == 100);
}
private static int CalculateSomethingExpensive()
{
result = //some sort of expensive operation here
return result;
}
[Conditional("DEBUG")]
private static void CheckResult(bool resultIsOK)
{
System.Console.WriteLine(resultIsOK ? "OK" : "not OK");
}
In this case, what compiler rules decide whether the expensive method is executed or optimised away? For example, is it guaranteed to be removed if it makes no changes to the state of any object?
I understand that the uncertainty can be removed by explicitly using #if but when one has a large code base with hundreds of Debug.Assert() statements, this can get unsightly very quickly.

So, with a little modification, here is what is compiled (under Release):
class Program
{
public static void Main(string[] args)
{
CheckResult(CalculateSomethingExpensive() == 100);
}
private static int CalculateSomethingExpensive()
{
var result = new Random().Next(100);//some sort of expensive operation here
return result;
}
[Conditional("DEBUG")]
private static void CheckResult(bool resultIsOK)
{
System.Console.WriteLine(resultIsOK ? "OK" : "not OK");
}
}
Which is pretty much the same as your example except modified to compile. Compiling it and then running it through the decompiler, results in this:
internal class Program
{
public Program()
{
}
private static int CalculateSomethingExpensive()
{
return (new Random()).Next(100);
}
[Conditional("DEBUG")]
private static void CheckResult(bool resultIsOK)
{
Console.WriteLine((resultIsOK ? "OK" : "not OK"));
}
public static void Main(string[] args)
{
}
}
You can see that the only difference is that the CheckResult call is removed from Main. This means that the full call is removed. Even if CheckResult or CalculateSomethingExpensive had side-effects, those will be removed.
The interesting thing is that the methods are still there in the compiled output, just the calls are removed, so don't use [Conditional(Debug)] to hide secrets used during debugging.

Related

Can I have two entry points in C#

Would it be possible to use two entry points in C# instead of just having the one. For example when I have this:
using System;
namespace learning
{
class cool
{
static void Main(string[] args)
{
}
}
}
Would it be possible to have another entry point such as secondary that the program executes once the main entry point has finished.
You may want to do something like this:
class Program {
public static void EntryPoint1(string[] args) {
// Code
}
public static void EntryPoint2(string[] args) {
// Code
}
public static void Main(string[] args) {
EntryPoint1(args);
EntryPoint2(args);
}
}
Just make sure to not modify args during EnteryPoint1 or if you want to, clone them like this:
class Program {
public static void EntryPoint1(string[] args) {
// Code
}
public static void EntryPoint2(string[] args) {
// Code
}
public static void Main(string[] args) {
EntryPoint1(args.Clone());
EntryPoint2(args.Clone());
}
}
In C#, you specify the entry point using the /main: compiler option.
Imagine that the code containing containing two main() methods as follow :
namespace Application {
class ClassA {
static void main () {
// Code here
}
}
class ClassB {
static void main () {
// Code here
}
}
To use ClassA.main() as your entry point, you would specify the following when compiling:
csc /main:Application.ClassA hello.cs
You can only have a single entry point, but you can write two separate methods, call the first one, and then the second one. You will achieve what you're describing.
using System;
namespace learning
{
class cool
{
static void Main(string[] args)
{
PartOne();
PartTwo();
}
void PartOne() {
// Something happens here
}
void PartTwo() {
// Something else happens here
}
}
}
Additionally (depending on how the program starts up) you can send in arguments to specify which method you want to execute (if you don't need both of them to execute). Then you can just do an "if/else" statement that will decide which method to run depending on the arguments passed into Main

Pointing a function to another

Suppose I have two functions:
void DoesNothing(){}
void OnlyCalledOnce(){
//lines of code
}
Is it possible to call OnlyCalledOnce and it actually run DoesNothing ? I imagine something like this:
void DoesNothing(){}
void OnlyCalledOnce(){
//lines of code
OnlyCalledOnce = DoesNothing;
}
and after that last line, whenever I called OnlyCalledOnce it would run DoesNothing.
Is it possible?
You can simply return early in OnlyCalledOnce like this: (assuming your DoesNothing example literally does nothing - it isn't needed)
bool initialized = false;
void OnlyCalledOnce()
{
if (initialized) return;
// firsttimecode
initialized = true;
}
The initialized variable will be true after first run.
Did you try to use delegate?
class Program
{
private static Action Call = OnlyCalledOnce;
public static void Main(string[] args)
{
Call();
Call();
Call();
Console.ReadKey();
}
static void DoesNothing()
{
Console.WriteLine("DoesNothing");
}
static void OnlyCalledOnce()
{
Console.WriteLine("OnlyCalledOnce");
Call = DoesNothing;
}
}
Another way you could solve this is to maintain a list of strings that represent the methods that have been called. The strings don't even have to be the method name, they just need to be unique to each method.
Then you can have a helper method called ShouldIRun that takes in the function's unique string and checks to see if it exists in the list. If it does, then the method returns false, and if it doesn't, then the method adds the string to the list and returns true.
The nice thing here is that you don't have to maintain a bunch of state variables, you can use this with as many methods as you want, and the methods themselves don't need any complicated logic - they just ask the helper if they should run or not!
public class Program
{
private static List<string> CalledMethods = new List<string>();
static bool ShouldIRun(string methodName)
{
if (CalledMethods.Contains(methodName)) return false;
CalledMethods.Add(methodName);
return true;
}
// Now this method can use method above to return early (do nothing) if it's already ran
static void OnlyCalledOnce()
{
if (!ShouldIRun("OnlyCalledOnce")) return;
Console.WriteLine("You should only see this once.");
}
// Let's test it out
private static void Main()
{
OnlyCalledOnce();
OnlyCalledOnce();
OnlyCalledOnce();
GetKeyFromUser("\nDone! Press any key to exit...");
}
}
Output
As already stated, you can use this:
private bool isExecuted = false;
void DoesNothing(){}
void OnlyCalledOnce(){
if (!isExecuted)
{
isExecuted = true;
//lines of code
DoesNothing();
}
}
If you have multiple threads etc, you can do a lock(object) ..
What's your problem with this?
void DoesNothing()
{
}
void OnlyCalledOnce()
{
DoesNothing();
}
It will run DoesNothing() once you run OnlyCalledOnce()

Automatically passing own type to function call

I'd like to pass a value when calling a function but want to omit to actually add it as a parameter.
To be more precise I'd like to write a logger that also prints which class called the logging function but don't want to always pass a "this" as a parameter.
Example code:
class static Logger{
public static void LogMsg(string msg, object objectCalling){
Print(objectCalling.GetType().Name + ": " + msg);
}
private void Print(string msg){
// print it
}
}
class SomeClass{
private void WriteTestLog() {
Logger.LogMsg("Testing!");
}
}
This should then create an output like: "SomeClass: Testing!"
I am not sure how to tackle this maybe I am just missing sth.
There are a few attributes which might be helpful:
CallerMemberNameAttribute: the name of the calling method or property;
CallerFilePathAttribute: the file path where the calling member is in;
CallerLineNumberAttribute: the line number within the file.
As you see, there is no attribute for the class name, but with the file path you might achieve the same level of information.
How to use this? Decorate an argument in your logging method with the attribute (of course, using the correct type and default).
public static void LogMsg(string msg, [CallerMemberName] string callingMember = null)
{
Print($"{callingMember}: {msg}");
}
And just call:
LogMsg("hello!");
You can use System.Runtime.CompilerServices with it's CallerMemberNameAttribute
Here is example:
using System;
using System.Runtime.CompilerServices;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
Logger.WriteLog("Hello");
}
}
public class Logger
{
public static void WriteLog(string msg, [CallerMemberName] string methodName="")
{
Console.WriteLine("Method:{0}, Message: {1}",methodName,msg);
}
}
}
You could create an extension method to do that as well as the answers above :
void Main()
{
SomeClass x = new SomeClass();
x.WriteTestLog();
int i = 1;
i.LogMsg("abc");
}
public static class Logger
{
public static void LogMsg(this object objectCalling, string msg)
{
Print(objectCalling.GetType().Name + ": " + msg);
}
private static void Print(string msg)
{
Console.WriteLine(msg); // print it
}
}
public class SomeClass
{
public void WriteTestLog()
{
this.LogMsg("Testing!");
}
}
If you really wish to extract the caller's type you can play with the stack trace:
[MethodImpl(MethodImplOptions.NoInlining)]
public static void LogMsg(string msg)
{
var caller = new StackTrace().GetFrames()[1].GetMethod();
Console.WriteLine($"{caller.DeclaringType}.{caller.Name}: {msg}");
}
But keep in mind that extracting the caller from the stack trace is a very expensive operation. Besides despite of the NoInlining it is not guaranteed that in an optimized build the caller itself is not inlined. I do not recommend to use it in a release build or if performance matters.

Force code to execute in order?

I am seeing a strange problem in my C# code. I have something like this:
public static class ErrorHandler {
public static int ErrorIgnoreCount = 0;
public static void IncrementIgnoreCount() {
ErrorIgnoreCount++;
}
public static void DecrementIgnoreCount() {
ErrorIgnoreCount--;
}
public static void DoHandleError() {
// actual error handling code here
}
public static void HandleError() {
if (ErrorIgnoreCount == 0) {
DoHandleError();
}
}
}
public class SomeClass {
public void DoSomething() {
ErrorHandler.IncrementIgnoreCount();
CodeThatIsSupposedToGenerateErrors(); // some method; not shown
ErrorHandler.DecrementIgnoreCount();
}
}
The problem is that the compiler often decides that the order of the three calls in the DoSomething() method is not important. For example, the decrement may happen before the increment. The result is that when the code that is supposed to generate errors is run, the error handling code fires, which I don't want.
How can I prevent that?
Add Trace or Logs to your code in IncrementIgnoreCount, DecrementIgnoreCount and HandleError function.
That will help you to view real call order.

C# Curly brackets issue

I'm following a tutorial on C# on making a text-based game and I ran into an issue right at the start. The following code:
namespace GameV2
{
class Level
{
private static Room[,] rooms;
#region Properties
public static Room[,] Rooms
{
get { return rooms; }
}
#endregion
public static void Initialize();
*{*
}
private static *BuildLevel*();
{
}
return false;
}
*}*
gives me 3 errors.
Error 1 Invalid token '{' in class, struct, or interface member declaration
Error 2 Expected class, delegate, enum, interface, or struct
Error 3 Type or namespace definition, or end-of-file expected
The italics represent the errors in order. Fr some reason Visual c# express won't let me use { in a method definition, and pushes my final } out of the code box. Any ideas on why this happens?
You don't have semicolons after methods. You may be confusing them for C
method prototypes.
BuildLevel should have a return type.
All statements have to be inside methods, you can only have declarations outside of methods
This should compile:
namespace GameV2
{
class Level
{
private static Room[,] rooms;
#region Properties
public static Room[,] Rooms
{
get { return rooms; }
}
#endregion
public static void Initialize()
{
}
private static bool BuildLevel()
{
return false;
}
}
}
public static void Initialize();
private static *BuildLevel*();
Those are declarations. They cannot be followed by { }. Remove the ; and it will work.
private static TYPEHERE *BuildLevel*();
This is missing a return type.
Remove the two ;
public static void Initialize()
{
}
private static BuildLevel()
{
}
public static void Initialize();
{
}
should be
public static void Initialize()
{
}
Remove the semicolons from the end of your function declarations (before the opening curly brace).
Watch out for the semicolons. You have semicolons between the method names and their bodies.
This may be the problem:
private static *BuildLevel*();
{
}
return false;
You didn't specify a return type, and the return false; should be inside the brackets.

Categories

Resources