Showing posts with label programing. Show all posts
Showing posts with label programing. Show all posts

Jan 21, 2026

Structs in C# are fun - Part 9/9: Conclusion

Leia este post em Português.

Lire cet post en français.

In the previous posts of this series we've learned that in some scenarios, despite the syntax leading us to believe the contrary, struct constructors may not be executed.

Being aware of this behavior is important and special care should be taken when defining public APIs (specially in libraries due to the potential reach of those) to avoid ending up with APIs that are unintuitive and/or error prone due to developers easily falling into the trap of using uninitialized struct1 members.

That said, this behavior is not new; problems like the ones discussed in post #5, #6 and #7 existed since the first versions of the language; however the introduction, in C# 10, of the ability to define parameterless constructors in structs adds more complexity and makes it more likely that developers will be exposed to such types2.

So, if you are consuming struct types be careful to not end up using uninitialized1 instances. By the other hand, take special care when defining new struct types, specially those with parameterless constructors or a constructor with all of its parameters being optional.

And so we reach the final post in this series. I hope you’ve enjoyed the journey, possibly have learned something new, and now feels better prepared to use and define your own structs.

As always, all feedback is welcome.

Have fun and see you in the next post!


  1. Note of clarification: From the perspective of the runtime, structs are guaranteed to be initialized (by zeroing out the whole struct) before being used. Initialization in the context of this series means that all struct fields/properties have been assigned meaningful values leaving the instance in a consistent/valid state.↩↩

  2. Prior to C# 10, the only way a developer would be exposed to such types would be by consuming assemblies built with a language supporting that feature, such as IL; personally I am not aware of a single instance of such types.↩

Mar 1, 2025

Structs in C# are fun - Part 8/9: Struct used as default argument values

Leia este post em Português.

Lire cet post en français.

In a previous post we looked at having default parameter values in struct constructors; this time we are going to have a quick look on what happens when we have struct parameters with default values. So, without further ado lets start with the following struct1:

struct S
{ 
    public int v = 42;
    public S(string s) { v = 13; }
}

and the following usage:

M();

void M(S s = new S()) => Console.WriteLine(s.v);

What you expect the output to be?

If you have been following this post series you probably know that this is a trick question and that neither 42 nor 13 are correct answers since that would require that either the field initializer and/or the constructor to be executed but the expression new S() used as the default parameter value does not implies a constructor invocation (after all there's no such parameterless ctor and if you feel tempted to add one the compiler will happily emit an error since in the presence of such ctor the expression in question does not represent a compile time constant anymore whence it cannot be used as a default parameter value).

When executed that code snippet will output 0 because the compiler simply initializes the full memory used to store the struct instance with zeros (0). By the other hand if you invoke method M() as follows2

M(new S("Foo"));

then the compiler will emit code to execute the constructor and the field initializer and 13 will be printed out, but this has nothing to do with the default parameter value anymore.

And with that we have explored the last not so intuitive struct behavior we intended to cover; next post will be the conclusion of this series.

As always, all feedback is welcome.

Have fun!


  1. Note that support for field initializers in structs was introduced in C# 10.↩

  2. The content of the string is not important in this context. All that matters is that a constructor is invoked.↩

Jan 2, 2025

Structs in C# are fun - Part 7/9: Required feature from C# 11 will not save your a** job.

Leia este post em Português.

Lire cet post en français.

The history of the current post is a little bit embarrassing.

During the process of defining the topics I'd cover I've learned about a C# 11 feature called required members which I naively though could be used to flag these scenarios so I planned to add a post showing how to achieve that; however during investigation/drafting1 the content, I've realized that that was not one of the goals of this feature and that there were multiple corner cases in which no warning would be emitted even though no constructor would be invoked2.

The main idea would be to to mark all members (field/properties) that would be initialized in the constructors as required and add the SetsRequiredMembers attribute to these constructors in such a way that in cases where no constructors (decorated with SetRequiredMembersAttribute) were to be invoked the compiler would emit a warning/error due to the non-initialization of such members.

This technique works relatively well if one wants to catch a very problematic scenario: instantiation of value types with a constructor in which all of its parameters are optional3. To make the discussion more concrete, lets take our last example from the previous post and modify it as described above:

Print(new S2());
Print(new S2(13));

void Print(S2 s) => System.Console.WriteLine(s.v);

struct S2
{ 
    public required int v;
    
    [System.Diagnostics.CodeAnalysis.SetsRequiredMembers]
    public S2(int i = 42)  => v = i;
}

With this change in place, instead of silently getting an instance of S2 initialized with zero (as opposed to the expected 42 if the constructor were to be invoked), we get the following error:

error CS9035: Required member 'S2.v' must be set in the object initializer or attribute constructor.

Not perfect, given that the message will probably be very confusing if one is (incorrectly, but understandably) expecting S2 constructor to be invoked, but there are other limitations rendering this approach even less viable:

  • Inability to detect constructors not being invoked (at least) in default expression and array instantiations.
  • Even in scenarios in which this would work it is impossible to guarantee that a ctor will be invoked (for instance, if we change the code at line #1 to new S2() { v = 5 }, no constructor will be invoked but no warning/error will be emitted either)

A more effective alternative (if you deploy your application as a managed one as opposed to AOTing it) to detect such scenarios is by explicitly asserting that struct instances have been initialized4 (either by a constructor or some other means) prior to accessing its members; since the code is being JITed one can implement this in a way users can control whether the check should be enforced or not and have very little (if any) performance impact when enforcing is disabled, as demonstrated below.

using System.Runtime.CompilerServices;

class Driver
{
    static void Main()
    {

        for(int i = 0; i < 100_000; i++)
        {
            var foo = new Foo(); // No constructor invoked... no warnings :(
            Thread.Sleep(100);
            foo.Use();
        }
    }

}

// The struct can be declared in a different assembly also. 
struct Foo
{
    // it is important for the field to be marked as `readonly`
    private static readonly bool _shouldValidate = Environment.GetEnvironmentVariable("VALIDATE_FOO") == "true";

    private int _i;
    private bool _isInitialized;

    public Foo(int v = 1) { _i = v; _isInitialized = true; }

    public void Use()
    {
        Verify();
        System.Console.WriteLine(_i);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)] // It is important to ask the JIT to inline this method for the optimization to be applied.
    private readonly void Verify()
    {
        if (_shouldValidate)
        {
            if (!_isInitialized)
            {
                throw new Exception("Foo constructor was not invoked; this may be due an array declaration or ...");
            }
        }
    }
}

The code use the field _shouldValidate to control whether correct initialization4 should be enforced or not (in this case more specifically, if the constructor has been executed). Notice that this field is declared as static readonly; this is very important since with this in place the JIT knowns that, for a given struct instance, once initialized, the field value will never change so it is free to handle _shouldValidate as a constant and to not generate code to check it in the if in line #XX; moreover, in case it is evaluated to false the JIT can remove the whole if statement (whence the close to zero overhead mentioned before).

You can see this JIT magic in action by opening a terminal, creating a console application with the code above and running:

DOTNET_JitDisasm=Use dotnet run -c Release

which:

  1. in unix like OSs, sets the environment variable DOTNET_JitDisasm value to Use and runs dotnet run -c Release.
  2. builds the application in release mode (-c Release), which is requirement for the optimization to be applied.
  3. instructs the JIT to dump the JITed assembly code for the method Use() by setting DOTNET_JitDisasm environment variable accordingly.

When executing that command line you should see zeros (0) and some assembly code being printed to the terminal multiple times; after some iterations you should be able to spot some assembly code resembling the one below (make sure to check the one that contains Tier1 as opposed to Tier0):

; Assembly listing for method Foo:Use():this (Tier1)
; Emitting BLENDED_CODE for X64 with AVX - Unix
; Tier1 code
; optimized code
; rsp based frame
; fully interruptible
; No PGO data
; 1 inlinees with PGO data; 0 single block inlinees; 0 inlinees without PGO data

G_M000_IG01:                ;; offset=0x0000
 
G_M000_IG02:                ;; offset=0x0000
       mov      edi, dword ptr [rdi]
 
G_M000_IG03:                ;; offset=0x0002
       tail.jmp [System.Console:WriteLine(int)]
 
; Total bytes of code 8

which is basically calling System.Console.WriteLine(_i) and returning, with no traces of the method Verify() invocation.

You can also play around with this example by running it as:

DOTNET_JitDisasm=Use VALIDATE_FOO=true dotnet run -c Release

in which case it will throw an exception (proving that uninitialized struct instances usage is detected)

or

DOTNET_JitDisasm=Use dotnet run -c Debug

in which case, no matter for how long the application runs, the assembly code generated for Use() will always call Verify() (i.e. optimization was not applied because application was built in debug mode)

With this approach one can be sure that no code is using uninitialized instances by simply running the code with the environment variable set to true and observing for exceptions.

As always, all feedback is welcome.

Have fun!


  1. here you can find some test code I used while exploring this topic.↩

  2. After realizing that I've changed the post's title :).↩

  3. This particular case is problematic due to the expectation that the behavior would match the behavior for classes↩

  4. Note of clarification: From the perspective of the runtime, structs are guaranteed to be initialized (by zeroing out the whole struct) before being used. Initialization in the context of this series of posts means that all struct fields/properties have been assigned meaningful values leaving the instance in a consistent state.↩↩

Jan 31, 2024

Les structures en C# sont amusantes - Partie 6/9: Struct avec des valeurs d'argument par défaut dans les constructeurs, ou, n'êtes-vous pas encore confus ?

Leia este post em Português

Read this post in english

  1. Les structures en C# sont amusantes
  2. Brève introduction aux Value Types vs Reference Types.
  3. Initialisation des champs dans les structures.
  4. Comportement des constructeurs dans structures.
  5. Des autres scénarios dans lesquels le comportement des constructeurs de structure peut vous surprendre.
  6. Struct avec des valeurs d'argument par défaut dans les constructeurs, ou, n'êtes-vous pas encore confus ? (cet post)
  7. Le modificateur required de C # 11 ne sauvegardera pas votre c*l emploi.
  8. Structure utilisée comme valeurs d'argument défaut.
  9. Bonus: L'evolution des structures en C#.

Dans les derniere posts, nous avons vu que le compilateur C# peut net pas exécuter le constructeur des structs dans certains scénarios. Malheureusement, l'expérience avec les constructeurs dans les structures, du moins à mon avis, peut devenir encore plus déroutante.

Pour illustrer mon point, supposons que vous ayez le code suivant :

Print(new S2()); 
Print(new S2(13));

void Print(S2 s) => System.Console.WriteLine(s.v);

struct S2
{ 
    public int v;
    public S2(int i = 42)  => v = i;
    public S2() => v = 84;
}

Quel résultat attendez-vous s’il est compilé/exécuté1 ?

  1. Le compilateur émettra une erreur en affirmant que new S2() est un appel ambigu.
  2. Il compile et génère 42, 13.
  3. Il compile et génère 84, 13.

La bonne réponse, qui peut surprendre certains développeurs, est qu'il se compile avec succès et affiche 84 et 13 (c'est-à-dire la troisième option).

Cela se produit parce qu'à la ligne 1, le compilateur C# considère le constructeur sans paramètre comme une meilleure correspondance (better match) que celui avec la valeur de paramètre par défaut excluant les options 1 et 21. Le bon côté est que même si cela n'est pas totalement évident, au moins ce comportement est cohérent entre les classes/structures.

Pourtant, avec les structures, cela peut devenir encore plus complexe/déroutant ; imaginez que vous avez exactement le même code que ci-dessus, la seule différence étant la suppression du constructeur sans paramètre :

Print(new S2()); 
Print(new S2(13));

void Print(S2 s) => System.Console.WriteLine(s.v);

struct S2
{ 
    public int v;
    public S2(int i = 42)  => v = i;
}

maintenant, c'est sûr qu'il imprimera 42, 13, n'est-ce pas ?

Non! Dans ce scénario, contrairement aux classes, un constructeur avec des valeurs par défaut pour tous ses paramètres n'est pas invoqué, même sur une new expression explicite2, ce qui signifie que le code ci-dessus imprimera 0 et 133.

Dans le prochain article, nous examinerons rapidement les membres requis C# 114 comme moyen d'aider à identifier les scénarios dans lesquels aucun constructeur n'est invoqué.

Comme toujours, tous les commentaires sont les bienvenus.

Amusez-vous!


  1. Pour être honnête, le comportement ici est le même pour les classes, donc au moins il est cohérent.↩↩

  2. la spécification des constructeurs sans paramètre dans les structures indique explicitement que ce comportement est le même que dans les versions précédentes de C#.↩

  3. Cela se produit parce que la ligne n°1 est équivalente à Print(default(S2)) ; pour plus de détails, voir cet article.↩

  4. Je suis conscient que ce n'est pas l'utilisation prévue de cette fonctionnalité, mais elle peut être utilisée pour signaler quelques instanciations de structure qui n'invoquent pas de constructeur.↩

Structs in C# are fun - Part 6/9: Struct with default argument values in ctors a.k.a, are you not confused yet ?

Leia este post em Português

Lire cet post en français.

In the previous post we saw that the C# compiler may not emit a ctor invocation in some scenarios. Unfortunately the experience with constructors in structs, at least in my opinion, may get even more confusing.

To illustrate this point, suppose you have the following code:


Print(new S2()); 
Print(new S2(13));

void Print(S2 s) => System.Console.WriteLine(s.v);

struct S2
{ 
    public int v;
    public S2(int i = 42)  => v = i;
    public S2() => v = 84;
}

What do you expect to happen when you compile/run this code1?

  1. Compiler will emit an error claiming new S2() is an ambiguous call.
  2. It compiles and outputs 42, 13.
  3. It compiles and outputs 84, 13.

The correct answer, which may surprise some developers, is that it compiles successfully and prints 84 and 13 (i.e, the third option).

That happens because in line 1 the C# compiler sees the parameterless constructor as a better match than the one with the default parameter value ruling out options 1 and 21. The bright side is that even not being totally obvious, at least this behavior is consistent across classes/structs,

However, with structs, it may get even more complex/confusing; imagine you have exactly the same code as above, with the only difference being the removal of the parameterless constructor:

Print(new S2()); 
Print(new S2(13));

void Print(S2 s) => System.Console.WriteLine(s.v);

struct S2
{ 
    public int v;
    public S2(int i = 42)  => v = i;
}

now, for sure it will print 42, 13, right ?

Nope! In this scenario, differently from classes, a constructor with default values for all of its parameters is not invoked, even on an explicit new expressions2 which means the code above will print 0 and 133.

In the next post we'll take a quick look into required members C# 11 feature4 as a way to help pin-pointing scenarios in which no constructor is being invoked.

As always, all feedback is welcome.

Have fun!


  1. To be fair the behavior here is the same for classes, so at least it is consistent↩↩

  2. The specification of parameterless constructors in structs explicitly states that this behavior is the same as in previous versions of C#↩

  3. That happens because line #1 is equivalent to Print(default(S2)); for more details see this post.↩

  4. I am aware that this is not the intended use of this feature but it may be used to flag struct instantiations that does not invoke a constructor.↩

Structs em C# - diversão garantida - Parte 6/9: Argumentos default em construtores de estruturas (você ainda não esta confuso ?)

Lire cet post en français.

Read this post in english

  1. Structs em C# - diversão garantida
  2. Rápida introdução à Value Types vs Reference Types
  3. Inicialização de campos em estruturas
  4. Comportamento de construtores em estruturas.
  5. Outros cenários em que o comportamento de construtores em estruturas podem te surpreender.
  6. Argumentos default em construtores de estruturas (você ainda não esta confuso ?). (este post)
  7. Modificador required do C# 11 não vai salvar seu c* trabalho.
  8. Estruturas usadas como valor default de argumentos.
  9. Bonus: Evolução das estruturas em C#.

Nos posts anteriores vimos que, em alguns cenários, o compilador C# pode não emitir invocaçcões de construtores de estruturas. Infelizmente a experiência com construtores em structs, pelo menos na minha opinião, pode ficar ainda mais confusa.

Para ilustrar esse ponto, suponha que você tenha o seguinte código:


Print(new S2()); 
Print(new S2(13));

void Print(S2 s) => System.Console.WriteLine(s.v);

struct S2
{ 
    public int v;
    public S2(int i = 42)  => v = i;
    public S2() => v = 84;
}

Qual resultado você espera observar ao compilar/executar o mesmo? 1

  1. O compilador emitirá um erro informando que new S2() representa uma chamada ambígua.
  2. Ele compila e gera 42, 13.
  3. Ele compila e gera 84, 13.

A resposta correta, que pode surpreender alguns desenvolvedores, é que o programa compila com sucesso e imprime 84 e 13 (ou seja, a terceira opção).

Isso acontece porque na linha 1 o compilador C# vê o construtor sem parâmetros como uma melhor correspondência (best match) que aquele com o valor do parâmetro default, descartando as opções 1 e 21. O lado bom é que mesmo não sendo totalmente óbvio, pelo menos este comportamento é consistente entre classes/estruturas,

No entanto, o comportamento de construtores com relação à estruturas pode ficar ainda mais complexo/confuso; imagine que você tem exatamente o mesmo código acima, com a única diferença sendo a remoção do construtor sem parâmetros:

Print(new S2()); 
Print(new S2(13));

void Print(S2 s) => System.Console.WriteLine(s.v);

struct S2
{ 
    public int v;
    public S2(int i = 42)  => v = i;
}

agora, com certeza o mesmo vai imprimir 42 e 13, certo?

Não! Neste cenário, diferentemente das classes, um construtor com valores padrão para todos os seus parâmetros não é invocado, mesmo em expressões new explícitas2 o que significa que o código acima irá imprimir 0 e 133.

Na próxima postagem, daremos uma olhada rápida em uma funcionalide do C# 11 conhecida como required members4 como uma forma de ajudar a identificar cenários nos quais nenhum construtor é invocado.

Como sempre, todo feedback é bem-vindo.

Divirta-se!


  1. Para ser justo, o comportamento aqui é consistente com o de classes.↩↩

  2. A especificação de construtores sem parâmetros em estruturas afirma explicitamente que esse comportamento é o mesmo das versões anteriores do C#.↩

  3. Isso acontece porque a linha #1 é equivalente a Print(default(S2)); para obter mais detalhes, consulte esta postagem.↩

  4. Estou ciente de que este não é o uso pretendido deste recurso, contudo o mesmo pode ser usado para sinalizar algumas instanciações de estruturas que não invocam um construtor.↩

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!

Les structures en C# sont amusantes - Partie 1/9

Leia este post em português

Read this post in English.

Les value types (et par conséquent, les structures) existaient dans .NET depuis sa création, mais ils sont toujours une source de confusion en 2023 (au moins pour moi). J'ai donc décidé de rassembler une liste de comportements, qui peuvent ne pas être si évidents pour certains développeurs .NET, laquelle j'en discuterai dans le série de futurs articles ci-dessous:

  1. Ce post.
  2. Brève introduction aux Value Types vs Reference Types.
  3. Initialisation des champs dans les structures.
  4. Comportement des constructeurs dans structures.
  5. Des autres scénarios dans lesquels le comportement des constructeurs de structure peut vous surprendre.
  6. Struct avec des valeurs d'argument par défaut dans les constructeurs, ou, n'êtes-vous pas encore confus ?
  7. Le modificateur `required`de C # 11 ne sauvegardera pas votre c*l emploi.
  8. Structure utilisée comme valeurs d'argument défaut.
  9. Bonus: L'evolution des structures en C#.

Avant de continuer, svp, notez que cette série reflète l'état actuel de C#, cet a dire, la version 11 (.NET 7.0).

Même si vous êtes un développeur C# expérimenté, j'espère que vous pourrez apprendre quelque chose ou, pourquoi pas, ajouter votre point de vue/contribution au sujet..

Comme toujours, tous les commentaires sont bienvenus.

Amusez-vous!

Feb 27, 2023

Fun with references in C# - Part I / II

Leia este post em português

Lire cet post en Français.

I'll begin 2023 (late February :)) posts with a quick puzzle about C#.

Given the program below answer the following questions:

1. What is its output ?

2. Can you spot/explain the issues in the code?

3. How could one pinpoint the issue?

Of course you are free to compile/run it, and I do encourage you to do so, but I do suggest to only do it after you have formulated an hypothesis or if only inspecting the code does not ring any bells.

See you in the next post.

Have fun!

Adriano

Amusement avec les références en C# - Partie I / II

Leia este post em português

Read this post in English.

Je commencerai les messages de 2023 (fin février :)) avec une petite casse-tête sur C#.

Compte tenu du programme ci-dessous, répondez aux questions suivantes:

1. Quelle est sa sortie ?

2. Pouvez-vous repérer/expliquer les problèmes dans le code ?

3. Comment identifier le problème ?

Bien sûr, vous êtes libre de le compiler/l'exécuter, et je vous encourage à le faire, mais je suggère de ne le faire qu'après avoir formulé une hypothèse ou si seulement inspecter le code ne vous dit rien. 

A bientôt

Amusez-vous!

Adriano

Diversão com referências em C# - Parte I / II

Read this post in English.

Lire cet post en Français.

Vou começar os posts de 2023 (no final de Fevereiro :)) com um pequeno quebra-cabeças em C#.

Dado o programa abaixo, responda as seguintes questões:

1. O que será impresso?

2. Você é capaz de apontar/explicar os problemas no mesmo?

3. Como poderíamos notar o problema apenas fazendo inspeção do código?

Claro que você pode compilar/rodar o programa (inclusive eu recomendo que você o faça), contudo seria interessante criar uma hipotese antes.

Até o próximo post.

Divirta se!

Adriano

Sep 30, 2022

Une petit casse-têtes C# 10

Leia este post em português.

Read this post in English.

Êtes-tu une développeur/développeuse utilisant C# au quotidien? Suives-tu les derniers C# 10 développements? Êtes-tu intéressé par les casse-têtes? 

Si tu as répondu oui a des questions ci-dessus, étant donné le programme suivant, pouvez-vous, en changeant uniquement le type du paramètre msg dans la méthode Foo(), modifier la sortie du programme pour n'imprimer que les lignes contenant des nombres pairs?

c'est-à-dire, changer la sortie du programme par :

au lieu de:

Bref, les réglés sont:

  1. C'est interdit de changer l’implémentation de la méthode  Foo(), sauf changer le type du paramétrer msg.
  2. C'est interdit de changer le loop for, n'importe en quelle manière.
  3. C'est interdit de utiliser IL post-processing
  4. Tous les autres types de changement das le source code sont valides.

Suivant tu peux trouver quelque conseils dans le cas tu ne savais pas déjà le réponse:

  1. La solution (au moins laquelle que je suis intéresse) dépend dans une fonctionnalité qui s'était amélioré sur la version 10 de la langage.
  2. Regarde le programme attentivement en cherchent pour les pièces non essentielles;  elles contiennent quelques indices importantes pour trouver la solution.

Dans le prochain post je montrerai et discuterai ma solution.

Amuse-toi.

Adriano

A small C# 10 programming puzzle.

Leia este post em português

Lire cet post en Français.

Are you a developer using C# in a day to day basis? Are you following the latest development, mainly in the C# 10 version? Are you interested in puzzles? 

If so, given the following program, can you, changing only the  type of the parameter msg in Foo() method,  change the output of the program to print only the lines containing even numbers?

I.e printing:

instead of:

Summarizing, the rules are:

  1. You cannot change Foo's  implementation in any way other than changing its msg parameter type.
  2. You cannot change the implementation of the for loop in any ways.
  3. You cannot rely on IL post-processing in any way (but it would be a nice exercise 😃)
  4. Any other changes to the source are acceptable

Some tips, in case you don't know the answer yet:

  1. The solution for the proposed challenge (at least the one I am interested) depends on a C# feature that has been improved in version 10
  2. Inspect the source with attention and look for suspicious code, they do contain some clues on how to achieve your goal.

In the next posts I'll show, and discuss, my solution to that. I am curious to see what other solutions exists.

Have fun!

Adriano

Mar 28, 2018

Recursos para se manter atualizado com a linguagem C#

Read this post in English.

Olá

É surpreendente a quantidade de informações que temos a nossa disposição atualmente. Quando eu comecei a estudar programação (a alguns anos atrás :) ), informação sobre programação era muito limitada (morar em uma pequena cidade do interior de São Paulo e não ser capaz de ler nada em Inglês não ajudava muito).

A situação não melhorou muito quando entrei na universidade (3 ~ 4 anos após meu primeiro contato com um clone do Apple IIe); sem dúvida eu tinha acesso a mais livros, mas os mesmos eram em inglês (que eu ainda tinha muita dificuldade em ler por sinal) e também não cobriam uma ampla gama de assuntos da área.

Para nossa sorte (ou não), atualmente temos tanta informação disponível que temos dificuldade para acompanhar as novidades o que nos traz ao tema deste post: Neste mar de informações disponíveis temos que nos concentrar nas que podem nos proporcionar o melhor retorno pelo nosso investimo.

Se tratando da linguagem C#, para mim, do ponto de vista do desenvolvimento da mesma, todos desenvolvedor C# deveriam, pelo menos, conhecer o repositório https://github.com/dotnet/csharplang, o qual se auto denomina, o "repositório oficial para o design da linguagem C#". 

Neste repositório você pode encontrar documentação relativa a funcionalidades existentes, e mais importante (em minha opinião), ainda em desenvolvimento (por exemplo, recentemente documentos referentes a algumas 
funcionalides da próxima versão da linguagem (7.3)  foram publicados). 

Lá você também encontra documentos sobre as várias reuniões de design da linguagem.(aqui você pode ver um vídeo, em inglês, descrevendo o processo de design e como você pode usar este repositório).

O mais interessante é que não estamos limitados a apenas consumir passivamente o conteúdo deste o repositório; como o mesmo é aberto qualquer um pode enviar sugestões de novas funcionalidades para a linguagem bem como participar de discussões sobre os vários recursos em desenvolvimento.

Happy coding ;)

Adriano

Keeping up with C# development

Leia este post em português

Hi

it is amazing how much information we have available nowadays. I remember when I started studding programming (some 30 years ago :) ), it was really hard to find information (ok, I used to live in a small city in Brazil and could not read English at all, but still, there were not a lot of information available about computers / programming). 

The situation did not improve much when I went to college (3 ~ 4 years after my first contact with an amazing Apple II clone); surely I had access to more books but unfortunately most of them were in English, and did not cover much ground (at least the ones I had available).

Luckily, nowadays we have plenty of information available (actually much more than what any single person can imagine consuming), which bring us to the topic of this post: As a C# developers we have some great resources at our disposal; from the language development perspective, in my opinion, every C# developer should, at least, be aware  of https://github.com/dotnet/csharplang, in their own words, the "official repo for C# language design". 

In that repository you can find documentation about existing and, most interesting, 
under development, language features. As an example, recently design documents for the upcoming C# 7.3 version have been pushed). There we can also find documents for each of the Design Meetings which can be invaluable information for those interested in following the language evolution more closely (here you can find a video describing the design process and how that repo is used).

Notice that you are not limited to consuming information. Since that repository is open, anyone can participate and add his/her own suggestions.

To summarize, if you are interested in following the development of C#, you should definitely keep an eye on that.

Happy codding.

Adriano

Jun 21, 2016

To infinity and beyond : more powerful .NET Metadata querying with LINQPad custom drivers and Mono.Cecil

In my last post I discussed how we can use LINQPad to query .NET metadata using .NET reflection. 

Even though that alone was already quite useful it has its own drawbacks:
  • No nice integration with LINQPad, requiring the user to load the assembly manually (even worse, forcing users to type the full assembly path)
  • No way to inspect / dump method bodies (so it is not possible, for instance, to find all methods that call into an specific method)
In order to overcome those limitations I decided to write a custom LINQPad driver for .NET assemblies (as we saw before this is not strictly necessary to use LINQ to explore .NET metadata, but it definitely can help to make the experience more pleasant/enabling some scenarios by, for instance, exposing some predefined Sources like all public types, members and the like).

You can read more about custom LINQPad drivers here, but in summary I created a static driver that exposes the following predefined query sources:
  • Types : A collection of all types (irrespective to accessibility and/or whether the type in question is a top level / inner type) from the assembly's main module.
  • PublicTypes: A collection of all public types from the assembly's main module.
In addition to that I've also introduced some convenience functions that can be used in the queries:
  • AsString(method): An extension method for MethodBody that converts a method body into a formatted string with it's IL instructions.
  • Calls(method): An extension method for a MethodDefinition / MethodBody that takes a method (either as a MethodInfo or a MethodReference) and returns true if the method in question is being called in the method body.
  • References(type): An extension method for a MethodDefinition / MethodBody that takes a type (either as a string, a TypeInfo or a TypeReference) and returns true if the type in question is being referenced in the method body.
  • Property(name): An extension method (for TypeDefinition) that returns a property definition if the type has a matching one or null otherwise.
  • Event(name): An extension method (for TypeDefinition) that returns an event definition if the type has a matching one or null otherwise.
  • Field(name): An extension method (for TypeDefinition) that returns a field definition if the type has  a matching one or null otherwise.
You can have a glimpse of those features in the following screenshot:


If you are interested in using this, all you need to do is to download Cecil.LINQPad.Driver.lpx and install it in LINQPad by clicking Add connection "link" then "View more drivers...", then "Browse" and finally selecting Cecil.LINQPad.Driver.lpx file. 

Of course you can also grab the source code from GitHub and build it for yourself ;)

Feel free to comment, make suggestions, report issues, ask questions, etc.

Have fun!

Para o infinito e além: consultas ainda mais poderosas sob metadados NET com drivers parta LINQPad e Mono.Cecil

No post anterior mostrei como usar o LINQPad para executar consultas em metadados .NET usando .NET Reflection, técnica que, apesar de muito útil, possui algumas limitações:
  • Zero integração com LINQPad, exigindo que o assembly seja carregado manualmente (ainda pior é fato de termos que digitar o caminho completo do assembly),
  • Como o .Net Reflection não expõe o corpo (instruções) de métodos, não é possível por exemplo, encontrar todos os métodos que executam algum outro método específico ou que acessem uma propriedade, etc.
Felizmente o LINQPad nos permite desenvolver / utilizar custom drivers que se integram muito mais naturalmente com o mesmo. No meu caso eu escrevi um que usa o Mono.Cecil (ao invés de .Net Reflection) para expor algumas fontes pré-definidas para consultas:
  • Types : Uma lista com todos os tipos (independentemente do tipo ser público ou não e/ou ser uma inner class) definidos no módulo principal do assembly.
  • PublicTypes: Uma lista composta por todos os tipos definidos publicamente.
Também introduzi as seguintes extensões (extension methods):
  • AsString(): Método que estende MethodBody retornando as instruções que compõe o corpo do método na forma de uma string.
  • Calls(method): Método que estende MethodDefinition / MethodBody retornando verdadeiro (true) caso o método passado como parâmetro seja executado pelo corpo do método estendido.
  • References(type): Método que estende MethodDefinition / MethodBody retornando verdadeiro (true) se o tipo passado como parâmetro for referenciado pelas instruções do corpo do método estendido.
  • Property(name): Método que estende TypeDefinition retornando a propriedade especificada pelo parâmetro (caso o tipo possua uma propriedade com o mesmo nome) ou null.
  • Event(name): Método que estende TypeDefinition retornando o evento que possua o nome igual ao passado como parâmetro ou null caso o tipo em questão não possua um evento com este nome.
  • Field(name): Método que estende TypeDefinition retornando o campo que possua o nome igual ao especificado no parâmetro ou null caso o tipo em questão não possua um campo com este nome.
Você pode ver um exemplo da utilização de tais métodos na imagem abaixo:


Para usar este Custom Driver você pode baixar o arquivo Cecil.LINQPad.Driver.lpx e instalar o mesmo no LINQPad clicando na opção Add connection,  depois em "View more drivers...", "Browse" e finalmente selecionando o arquivo que você acabou de baixar (Cecil.LINQPad.Driver.lpx). 

É claro que você também pode baixar o source do mesmo do GitHub e compilar / instalar ;)


Uma vez instalado, o mesmo aparecerá na lista de opções de drivers disponíveis:



Pressione o botão Next e, a seguir selecione o assembly que você deseja fazer consultas. Lembre-se de, após abrir o assembly, clicar no dropdown "Connection" para selecionar a conexão que o LINQPad deve usar para rodar as consultas, ou seja, qual assembly deve ser usado como fonte nas consultas. No exemplo abaixo o assembly Boo.Lang.Parser.dll será usado:

Pronto. Agora você já pode rodar suas consultas LINQ!

Have fun!

Jun 16, 2016

Querying .NET assemblies with LINQPad

Since 2008 I have not only been playing / working with .NET on a daily basis; I've also done quite a lot of work with .NET assemblies and, as result, quite frequently I find myself trying to answer questions like:
  • How many types in the assembly are value types?
  • How many types exposes more than x properties?
  • Do we have any interfaces / types that does not conform to some specific naming convention?
  • etc.
In order to answer these questions I used to either write a quick program (with the help of Mono.Cecil) or ended up having some fun time with regular expressions (of course, running these regular expressions on the source code instead of the built assemblies). These solutions work relatively well but they have some serious drawbacks: i) lots of repetitive work, ii) it is harder to extract information from the source than from assemblies; iii) some times I don't have any source code at all, only the assembly, etc.

Since last Hackweek this was set to change! For some reason I can't explain (it is as if I have been in Mars for the last couple of years ;) I failed to even realize how powerful / flexible LINQPad has become; it is not the case that I was not aware about the tool itself; I knew LINQPad for some time (lets say, for 6 ~ 7 years) but I've never used it util last May; at that time a bunch of team mates were using it to quickly check generated IL for some C# code snippet and since I was participating in the same project I also needed to the same, so I decided to give it a try.

After returning to my daily tasks I sat one day and started experimenting with the idea of running queries on .NET assemblies for a couple of hours, and ended up really happy with the outcome. Actually, it was so easy that I have no idea why it took me so long to start using it: basically we can use .NET reflection and LINQ for Objects (as you can see in the following example):

var a = Assembly.LoadFrom(@"S:\Unity\Editor\Data\Managed\UnityEngine.dll");
var result = from t in a.GetTypes()
             where Char.IsLower(t.Name[0])
             select t.FullName;

result.Dump();

or, in other words, show me all the types with a name starting with a lowercase char!

That is it, simple like that. The best part is that it is plain C# using LINQ and reflection to navigate through the .NET metadata.

Of course there's (almost) nothing specific to LINQPad in that code snippet; to me, the value that LINQPad aggregates lies on how easy and natural it looks like to use it to type such queries without the need to write / compile a separate application and the quick iteration times it enables.

If you want to try it also just copy / past that code to LINQPad, change the assembly path to one that makes sense to you and run (by pressing F5):




Once we have a way to easily run standard LINQ queries over assemblies we can unleash our imagination and rely on LINQPad power. But, before you get too excited, this approach does have one caveat though: you'll need to have a good grasp about .NET reflection to be able to use it effectively.

In my next post I'll write a custom LINQPad Driver in order to use Mono.Cecil instead of .NET Reflection making it even easier / more flexible to use!

Have fun!

Leia este post em Português.