2017-09-26 10 views
2

Lorsque j'exécute le code suivant, j'obtiens RuntimeBinderException: 'object' does not contain a definition for 'SetIt'.Echec dynamique de la classe interne privée

public interface IInput { } 

public interface IThing<in TInput> 
{ 
    void SetIt(TInput value); 
} 

public class ThingMaker 
{ 
    private class Thing<TInput> : IThing<TInput> 
     where TInput : IInput 
    { 
     public void SetIt(TInput value){} 
    } 

    private class Input : IInput {} 

    public IThing<IInput> GetThing() 
    { 
     return new Thing<IInput>(); 
    } 

    public IInput GetInput() 
    { 
     return new Input(); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var thingMaker = new ThingMaker(); 

     var input = thingMaker.GetInput(); 
     dynamic thing= thingMaker.GetThing(); 

     thing.SetIt(input); 
    } 
} 

Si je passe thing à un var il fonctionne très bien. Donc, clairement, thing a SetIt. Comment ça se passe quand j'utilise dynamique? Est-ce que tout ce qui fonctionne comme var ne devrait pas fonctionner quand c'est dynamic?

Je pense que cela a quelque chose à voir avec Thing<TInput> étant une classe interne privée parce qu'elle fonctionne quand je la rends publique.

Répondre

1

Voici un exemple plus simple de votre problème:

class A 
{ 
    class B 
    { 
     public void M() { } 
    } 

    public static object GetB() { return new B(); } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     dynamic o = A.GetB(); 

     o.M(); 
    } 
} 

Les génériques et les interfaces sont juste une distraction.

Le problème est que le type B (ou dans votre cas, Thing<IInput>) est une classe privée, et donc sur le site d'appel, ne peut pas résoudre à ce type réel. Rappelons que dynamic est simplement une variable object mais où la compilation a été reportée jusqu'à l'exécution. Il n'est pas prévu de vous laisser faire des choses à l'exécution que vous ne seriez pas en mesure de faire autrement, et "ne serait pas en mesure de le faire" est jugé en fonction du type accessible sur le site d'appel (qui cas, est object).

En ce qui concerne le classeur d'exécution, le type est simplement object (d'où le message d'erreur vous indiquant que object ne contient pas le membre que vous voulez).

Bien sûr, il est théoriquement possible que dynamic ait pu être implémenté différemment, et pourrait faire une recherche plus approfondie des types valides qu'il pourrait traiter l'objet comme dans le but de lier des membres à l'objet (interfaces implémentées) plutôt que juste le type réel de l'objet). Mais ce n'est pas la façon dont il a été implémenté, et cela aurait été beaucoup plus coûteux (à la fois en termes de conception et d'implémentation, et bien sûr en termes de coût d'exécution du code qui utilise dynamic).

lecture connexes (sans doute en double):

Is this a bug in dynamic?
Is this a hole in dynamic binding in C# 4?