Showing posts with label english. Show all posts
Showing posts with label english. Show all posts

Jun 30, 2023

Structs in C# are fun - Part 1/9

Leia este post em português

Lisez cet post en french.

Value types (and consequently, structs) existed in .NET since its inception, yet they are still a source of confusion in 2023 (at least for me). So I decided to collect a list of subjects, that may or may not be so obvious to some .NET developers, and I'll discuss them in the following posts (I'll update the list adding links as I post about each topic):

  1. This post.
  2. Brief introduction to Value Types vs Reference Types.
  3. Field initialization in structs.
  4. Constructors and struct behavior.
  5. Other scenarios in which struct constructors behavior may surprise you.
  6. Struct with default argument values in constructors, a.k.a, are you not confused yet ?
  7. `required` feature from C# 11 will not save your a** job.
  8. Struct used as default argument values.
  9. Bonus: Struct evolution in C#.

Before continuing, note that this series reflects the current state of C# as of version 11 (.NET 7.0).

Last, but not least, even if you are an experienced C# developer I hope you can learn something or, why not, add your own perspective/contribution to the subject.

As always, all feedback is welcome.

Have fun!

Jan 21, 2016

Finding references to assemblies


The current task at my job requires me to patch (a fancy name for change) .NET assemblies, sometimes adding new members, sometimes changing type references, sometimes messing with the method implementation and sometimes doing a bit of all.

From time to time I need to find out why a assembly (A) has a reference to some other assembly (B); basically what I need to know is which type/member(s) from assembly B is being used by assembly A.

One particularly easy way (IMO) is to simply ildasm assembly A and look for references to B; in order to accomplish that you can do something like:


c:\temp> ildasm /all /out=c:\temp\assembly-a.il assembly-a.dll

After you generated the CIL from your assembly your next step is to search for the name of the assembly you want to find references for (in this example, Assembly_B); you'll find one or more (actually one for each referenced assembly) sessions in the IL code like:

.assembly extern /*23000005*/ Assembly_B
{

}

Now, you can either search for the name Assembly_B or by the number to its left (in this case 23000005)

.assembly extern /*23000005*/ Assembly_B
{
  .ver 1:0:0:0
}
.
.
.

IL_0006:  /* 28   | (0A)0000B2       */ call instance void [Assembly_B/*23000005*/]NamespaceName.TypeName::DoSomething()
.
.
.

In this example assembly A is using the instance method DoSomething() from type TypeName in namespace NamespaceName from assembly B.

What do you think?

Happy coding.

(Leia este post em português)

Mar 5, 2014

Running scripts on google drive documents

Hi.

I admit I have always looked to "cloud based" document editing (such as google drive, Microsoft Office 365, etc) with certain dislike, mainly due to the misconception that these applications would not allow me to use my precious scripts (after all, any true developer shall use scripts everywhere, right? ;)

Even though I somewhat disliked the idea, I ended up ceding (the convenience of having it available anywhere is so hard to ignore :) and,for some time, I have been using one spreadsheet to store a piece of information I use on a monthly basis.

It happens that last week I decided that one of the tasks involving that spreadsheet should be automated (basically, given some condition I'd like to add some information to a specific cell, which is a perfect job for a script) so I was considering moving the spreadsheet to my box and use LibreOffice (which I highly recommend, by the way) to edit it. 

While I was poking around my google spreadsheet menus, I stumbled in "Tools/Script Editor" menu option and realized that my resistance in using such online solutions had no ground whatsoever, i.e, it was just prejudice from my side :( I just selected that menu option and voila, scripts with debugging support!

That is all I needed! Some time (and a lot of keystrokes) later and I had my first script running; but the best was yet to come: not only I was able to reference my newly created function, but I could also schedule it to run from time to time! (that's exactly what I was looking for).

Following you can see my script:
function checkDate() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheets()[0];       
    
  var range = sheet.getRange("A1");
  
  var now = new Date();
  
  if (now.getHours() <= 10 || (now.getHours() >= 15 && now.getMinutes() > 30) || (now.getHours() >= 13 && (now.getHours() <= 14 && now.getMinutes() < 30)) ) {    
    range.setBackground("ORANGE");
    range.setValue("CLOSED");
  }
  else {
    range.setBackground("GREEN");
    range.setValue("OPEN");
  }
}
And it worked like a charm.

To my astonishment, today I figured it out that I can even execute WebServices (SOAP) from within my scripts (and of course I put it in action immediately) ! 

Happy Coding!

(Leia, uma versão extendida, deste post em portugues)

Feb 26, 2014

Useful command line utility: Clip

Are you a heavy Windows console user? Have you ever copied the output from a program to the clipboard by using the context menu? Well, are you aware of clip.exe that comes with Windows (at least it is present on Windows 7 and newer) ? 

It simply copy whatever it gets from the standard input to the clipboard! So you can do things like:


c:\temp>dir | clip

And get the contents of dir output to the clipboard (and of course, now you can past it wherever you want)!

Of course you can also redirect the standard input:
c:\temp>clip < file.txt

Happy coding!

(this post in portuguese)

Oct 26, 2013

Closures in C# - Answer


In the previous post I've asked what would be the output of a simple C# application:

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
   private static void Main(string[] args)
   {
      foreach (var func in GetFuncs1())
      {
         Console.WriteLine("[first] {0}", func());
      }

      foreach (var func in GetFuncs2())
      {
         Console.WriteLine("[second] {0}", func());
      }
   }

   private static List<Func<int>> GetFuncs1()
   {
      var fs = new List<Func<int>>();

      for (int i = 0; i < 3; i++)
      {
         fs.Add(() => i);
      }
      return fs;
   }

   private static List<Func<int>> GetFuncs2()
   {
      var fs = new List<Func<int>>();

      foreach (var i in Enumerable.Range(0, 3))
      {
         fs.Add(() => i);
      }
      return fs;
    }  
}
The correct answer is: it depends!

In order to understand the issue you need to undertand Closures and captured variables in C# (for a deeper understanding about these subjects I recomed reading here and here).

Basically in both methods (GetFuncs1 and 2) we are creating lambda expressions that references a local variable (i); since the CLR garantees that the memory allocated for such variable will be reclaimed as soon as it is not referenced, i.e, long before the usage of the lambda expression, the C# compiler "captures" the variable (if you are curious about how it does it, open the assembly using ILDASM or ILSpy to inspect the IL code, I do recommend) and here start our issues.

As I said the compiler captures the variable, not its value; so, calling GetFuncs1() produces code that is equivalent to something like (see the highlighted lines 20, 25-28 and 29) (the actual code is quite different but for our purposes the following code can be seen as equivalent):

using System;
using System.Collections.Generic;

class Program
{
 private static void Main(string[] args)
 {
  foreach (var func in GetFuncs1())
  {
   Console.WriteLine("[first] {0}", func());
  }
 }

 private static List<Func<int>> GetFuncs1()
 {
  var fs = new List<Func<int>>();

  for (ret = 0; ret < 3; ret++)
  {
   fs.Add(ret_func);
  }
  return fs;
 }

 private static int ret_func()
 {
  return ret;
 }

 private static int ret;
}
That means that we are always calling ret_func() and this function will return the value of ret which is updated in the for loop!

Ok, so now you understand why the output was 3,3,3 but two questions come up (at least):

  1. Is there a way to avoid this behavior so the output would be 0, 1 and 2 ?
  2. Why the hell I said that the output of the program "depends" ? And more importantly, depends on what?
The answer for the first question is yes; simply declare a new variable inside the for loop and assign "i" to it (line 20), then return the value of this new variable from within the lambda expression (line 21) :
using System;
using System.Collections.Generic;

class Program
{
 private static void Main(string[] args)
 {
  foreach (var func in GetFuncs1())
  {
   Console.WriteLine("[first] {0}", func());
  }
 }

 private static List<Func<int>> GetFuncs1()
 {
  var fs = new List<Func<int>>();

  for (int i = 0; i < 3; i++)
  {
   var capture = i;
   fs.Add(() => capture);
  }
  return fs;
 }
}
Running the application now produces the expected result. What changed is that now, since we are creating a new variable in every iteration, the compiler will emit code equivalent to:
using System;
using System.Collections.Generic;

class Program
{
 private static void Main(string[] args)
 {
  foreach (var func in GetFuncs1())
  {
   Console.WriteLine("[first] {0}", func());
  }
 }

 private static List<Func<int>> GetFuncs1()
 {
  var fs = new List<Func<int>>();

  for (int i = 0; i < 3; i++)
  {
   var h = new Holder {value = i};
   fs.Add(h.GetIt);
  }
  return fs;
 }

 class Holder
 {
  public int value;

  public int GetIt()
  {
   return value;
  }
 }
}
Again, now it became pretty easy to understand why we get the expected output; in each iteration the compiler is simply instantiating a new object to hold the value of "i" at that point in time.

Ok, so from now on, everytime you create lambda expressions / anonymous functions that capture local variables I am sure you'll pay attention and make sure you get the behaviour you want.

Regarding the second point, i.e, the "depends" part, if this blog happens to have more than a few readers I am sure that, when running the program, some of you got "unexpected" different outputs twice (i.e, 3,3,3 and 2,2,2) while some of you got 3,3,3 and 0,1,2!

The difference? The version of the C# compiler used!

See the picture below:

It happens that in C# 5 the behavior for captured variables of a foreach loop has changed! In this case the compiler will emit code as if in each iteration a new local variable were allocated (the same trick I showed you before); if you followed me you now understand why when compiling with VS 2012 the code produced the expected result.

Now the 1 million dollars question: why on earth the version that uses a simple for has not been updated with the same behavior? Well, I don't have (and I don't pretend to have) the definitive answer. What I can say is that IMHO it is at least "confusing". New developers (which are most likely unaware of this behavior) will, invariably, be caught by this at least once (but it can be twice)!

If these new developers happen to first use a for loop (always with lambdas / anonymous methods capturing local variables) they may find themselves wondering why their lambdas/anonymous methods are observing the updated value of a captured variable and then, when they finally realize what's going on, they will tend to use the "declare a local variable in each iteration" trick everywhere (including in foreach loops). By the other hand if these developers happen to first use a foreach loop then they will most likely find themselves wondering why they observe different behaviors when using lambdas/anonymous methods!

Even though I understand the reasoning in this discussion I don't fully agree - parts of my brain still thinks this simply introduces inconsitencies - but this is just my opnion.

If you are interested in reading about this topic in the C# language specification, it can be found in chapter 8.8.4.

What do you think?

Sep 17, 2013

Useful utility: ConEmu

Have you ever used cmd.exe (a.k.a Windows Console)? In my day to day tasks usually I have from 2 ~ 3 consoles open, which brings me to this post.

Lets be fair: Anyone that has used any *nix based shell (bash comes to my mind), usually considers (seriously) moving to Linux or some *nix based OS ;)

Even though I do recommend using a different OS, such a radical change is not required all you want is a better experience when using a console; on Windows, there are some alternatives to cmd.exe; for instance, I have used console2 for some time and recently I switched to ConEmu (mostly because it has been updated more frequently); in any case I do recommend you to take the time to check both to see which one you adapt better, if any :).

Since I started using such console replacements I don't miss cmd.exe even for a second ;)

(Este post em Português)


Happy coding.

Sep 4, 2013

Blogging experiments....

Hi,

Even though in the beginning I used to post in portuguese (my native language) I decided to switch to english to force me to write more in this language.

Although I am still firm believer that anyone interested in information technology field do need to be able to read english I came to the conclusion that posting in portuguese is also valuable so, starting with this post I'll experiment posting in both english / portuguese.

What do you think? 

If I get no feedback then I may decide switching back to english only posts :).

(you can read this post in portuguese)

Happy coding!