50 votes

Y a-t-il un problème avec le mot-clé dynamic en C# 4.0 ?

Il y a un comportement étrange avec l'utilisation dynamique de C# 4.0 :

using System;

class Program {
  public void Baz() { Console.WriteLine("Baz1"); }
  static void CallBaz(dynamic x) { x.Baz(); }

  static void Main(string[] args) {
    dynamic a = new Program();
    dynamic b = new { Baz = new Action(() => Console.WriteLine("Baz2")) };

    CallBaz(a); // ok
    CallBaz(b); // ok
    CallBaz(a); // Unhandled Exception:
    // Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
    // The name 'Baz' is bound to a method and cannot be used like a property
  }
}

J'utilise Visual Studio 2010 Release Candidate.

S'agit-il d'un bogue ? Si c'est le cas, sera-t-il corrigé dans la nouvelle version ?

32voto

Chris Burrows Points 1091

Je peux confirmer qu'il s'agit bien d'un bogue. La description rapide de ce qui ne va pas est la suivante : Dans CallBaz, il y a un seul callsite qui est invoqué trois fois. Ce callsite est un InvokeMember, parce que c'est la meilleure supposition que le compilateur puisse faire étant donné la syntaxe C#, malgré le fait qu'il pourrait, en réalité, se résoudre à un GetMember suivi d'un Invoke.

Lors de la seconde exécution du callsite, c'est bien cette liaison que le runtime trouve. Il produit donc un report vers un GetMember suivi d'un invoke. Le problème est que ce report ne se limite pas correctement au cas où l'argument est de type anonyme. Par conséquent, lors de la troisième exécution, le report est activé et le GetMember tente de se lier à Program, ce qui échoue bien sûr.

Merci de l'avoir trouvé. Comme le souligne Eric, nous en sommes à un stade très avancé et il devient difficile de résoudre les problèmes avant la livraison. Mais nous voulons aussi livrer le bon produit. Je vais faire ce que je peux pour résoudre ce problème, même si je n'y parviendrai peut-être pas. Si vous trouvez autre chose, n'hésitez pas à me contacter =)

UPDATE :

Bien que je ne puisse garantir ce à quoi ressemblera la version finale de VS 2010 et de C# 4 lorsqu'elle sera livrée, je peux dire que j'ai réussi à faire passer ce correctif. La version d'aujourd'hui se comporte correctement pour votre code. Sauf catastrophe, vous verrez ce problème corrigé lors de la sortie de la version. Merci encore. Je vous dois une bière.

11voto

Eric Lippert Points 300275

Cela semble suspect. Je vais l'envoyer en test et nous verrons ce qu'ils en disent.

Juste pour fixer les attentes : s'il s'agit d'un bogue, et qu'il n'a pas déjà été trouvé et corrigé, il y a de fortes chances qu'un correctif ne soit pas inclus dans la version finale.

Merci d'avoir attiré notre attention sur ce point !

8voto

Thomas Levesque Points 141081

Il s'agit d'un bogue sérieux...

Notez que cela fonctionne parfaitement si vous utilisez un ExpandoObject au lieu d'un type anonyme :

using System;
using System.Dynamic;

class Program {
  public void Baz() { Console.WriteLine("Baz1"); }
  static void CallBaz(dynamic x) { x.Baz(); }

  static void Main(string[] args) {
    dynamic a = new Program();
    dynamic b = new ExpandoObject();
    b.Baz = new Action(() => Console.WriteLine("Baz2"));

    CallBaz(a); // ok
    CallBaz(b); // ok
    CallBaz(a); // ok
  }
}

Le problème semble donc spécifique aux objets anonymes...

Apparemment, lors du deuxième appel à CallBaz(a) le DLR tente toujours d'accéder à Baz en tant que propriété, parce que c'était une propriété du type anonyme. Je soupçonne que le classeur C# met en cache la résolution des appels pour améliorer les performances, mais dans ce cas, il est clairement cassé...

2voto

Paul Creasey Points 15663

C'est la même chose pour moi, je vous suggère de le signaler. aquí .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X