2010-07-05 5 views
1

J'ai un peu de mal avec certains moulages que je n'arrive pas à résoudre.Casting object to generic T

J'ai cette interface et les implémentations suivantes:

public interface IConfigureServiceOnServer 
{ 
    void Configure(Service service); 
} 

public sealed class ServiceConfigurator : IConfigureServiceOnServer 
{ 
... 
} 

je charge ces types lors de l'exécution en utilisant la méthode suivante un dictionnaire (qui contient les noms d'assemblage et de type):

public static T Resolve<T>(string type, params object[] values) where T : class 
     { 
      var split = refs[type].Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); 
      var assembly = Assembly.LoadFrom(split[0] + ".dll"); 
      var instance = assembly.CreateInstance(
       split[1], // the name of the Type to instantiate 
       true, 
       BindingFlags.CreateInstance, 
       null, 
       values, // the params to use in the constructor 
       null, 
       null); 
      T ret = (T)instance; //also tried with 'instance as T' 
      return ret; 
     } 

je reçois une exception coulée invalide lors de l'appel comme celui-ci

Resolver.Resolve<IConfigureServiceOnServer>("serviceconfiguration", ""); 

I c An't tout à fait comprendre pourquoi je reçois cette exception parce que le même code fonctionne pour la prochaine interface et sa mise en œuvre:

public interface IServiceManager 
{ 
    void Create(); 
    void Configure(); 
} 

public sealed class Service : IServiceManager 
{ 
... 
} 

Toutes les idées pourquoi le même code fonctionne pour le 2ème exemple et non pour la première?

Merci d'avance.

EDIT:

Quand je suis débogage et j'arrêter l'exécution juste avant le retour dans la méthode Resolve je peux utiliser la fenêtre immédiate - i tester la distribution et il fonctionne.

EDIT2: Voici le message d'exception:

Unable to cast object of type 'Codegarten.Controller.Configuration.Service.ServiceConfigurator' to type 'Codegarten.Controller.Configuration.IConfigureServiceOnServer '. 

EDIT3: Un peu plus d'info - Quelqu'un a suggéré le type chargé à l'aide de réflexion pourrait être mal si je l'ai fait un peu plus de débogage. Je vérifié pour voir si le type chargé en œuvre l'interface souhaitée en utilisant la fenêtre immédiate en studio visuel:

>instance.GetType().GetInterfaces() 
{System.Type[1]} 
    [0]: {Name = "IConfigureServiceOnServer" FullName = "Codegarten.Controller.Configuration.IConfigureServiceOnServer"} 

SOLUTION
Ok, le problème était dû à la méthode de Assembly.LoadFrom, qui a chargé l'ensemble dans un contexte différent de celui des applications. J'ai résolu ce problème en utilisant Assembly.Load à la place. J'ai résolu ce problème en utilisant Assembly.Load à la place.

+0

Une raison pour laquelle vous ne pouvez pas utiliser un conteneur IoC? –

+1

Au moment où vous obtenez l'exception, vous pouvez afficher le type de T et le type d'instance dans le débogueur. –

+0

@Mattias: Le conteneur IoC n'est pas une option car ils offrent beaucoup plus que ce dont j'ai besoin. Je peux simplement charger les types en utilisant l'activateur @Chris: Bien sûr, je vais éditer le premier message avec le message d'exception. – Alka

Répondre

1

Je suppose que le problème que vous rencontrez est que les types sont chargés dans différents contextes. L'utilisation de Assembly.LoadFrom chargera le type dans le contexte LoadFrom, tandis que l'interface que vous avez définie se trouve dans le contexte Load. Voir ici pour plus d'informations sur le contexte LoadFrom.

Chargez-vous les assemblages à partir d'emplacements différents? Si ce n'est pas le cas, vous pouvez utiliser Assembly.Load pour charger l'assemblage en utilisant le nom d'affichage, cela devrait charger le type dans le même contexte que l'interface et votre distribution devrait fonctionner puisque les identités de type correspondront. Si cela fonctionne, mieux vaut utiliser le nom qualifié de l'assembly et utiliser Type.GetType pour charger le type.

+0

Ok, je vais devoir le tester demain et je reviendrai à vous . Je pense que vous avez raison sur l'idée de contexte que la documentation LoadFrom dit qu'il peut y avoir InvalidCastException avec son utilisation. Existe-t-il un moyen de vérifier le contexte sur lequel un type est chargé? – Alka

+0

Il semble que vous aviez raison sur les types chargés dans différents contextes. J'ai utilisé Assembly.Load à la place et cela fonctionne. Pourquoi LoadFrom échoue-t-il si les assemblys se trouvent dans le même répertoire que le fichier .exe? – Alka

2

Êtes-vous absolument sûr que le type IConfigureServiceOnServer dans la ligne

Resolver.Resolve<IConfigureServiceOnServer>("serviceconfiguration", ""); 

compile exactement le même type dans le même espace de noms dans le même ensemble que celui de la définition de votre classe? Je devine à partir des noms que vous avez une sorte de service Web dans votre solution. Le code IConfigureServiceOnServer dans un emplacement se réfère à l'interface réelle définie dans le service, et IConfigureServiceOnServer dans l'autre emplacement renvoie à la copie proxy définie dans la référence du service?

Alternativement, la classe ServiceConfigurator peut compiler à un type différent de celui qui est actuellement instancié dans votre code de réflexion.

MISE À JOUR:

Je vous suggère de déboguer la propriété AssemblyQualifiedName de la classe et de son interface pour (a) le type défini d'origine, et (b) une instancié par réflexion.

+0

D'accord, plus d'un type IConfigureServiceOnServer à l'œuvre ici. –

+0

Non, je n'utilise pas de services Web. Je ne fais que mapper des services (comme dans d'autres applications) dans mon application C#. J'ai look (ildasm) et l'assemblage qui contient les deux types et l'interface construite correctement. – Alka

+0

Assez juste, mais le fait demeure qu'une exception disant "ne peut pas lancer X à Y", signifie que X n'hérite pas ou n'implémente pas Y. Pour que cela se produise, soit X! = X ou Y! = Y, si vous voyez ce que je veux dire. –