2009-10-20 19 views
19

Mam klasę (TabControlH60), która dziedziczy z klasy bazowej (UserControl) i implementuje interfejs (IFrameworkClient). Wykonuję instancję obiektu przy użyciu klasy .NET Activator. W przypadku zwróconej instancji mogę rzutować na klasę bazową UserControl, ale nie na interfejs. Wyjątek, który otrzymuję, znajduje się poniżej kodu snipet. Jak przesyłać do interfejsu?.NET: Nie można rzutować obiektu na interfejs implementuje

object obj = Activator.CreateInstance(objType); 
Type[] interfaces = obj.GetType().GetInterfaces(); // contains IFrameworkClient 

m_Client = (UserControl)obj;     // base class cast works 
IFrameworkClient fc = (IFrameworkClient)obj; // interface cast fails 

// Note: The (IFrameworkClient)obj cast works fine in the debugger Watch window. 
{"Unable to cast object of type 'FPG.H60.AFF.TabControlH60' to type 
    'FPG.AFF.Interfaces.IFrameworkClient'."} 

Odpowiedz

0

Użyj jako operatora :)

... 
m_Client = obj as IFrameworkClient; 
if (m_Client != null) //Remember to check for null in case the cast fails 
    ... 
... 
+0

Po ponownym przeczytaniu twojego pytania, nie sądzę, że to było to, czego chciałeś. Przepraszam :) – cwap

+1

Operatorem "as" jest dokładnie to, czego nie chcesz * używać podczas debugowania błędów odlewania (po cichu połkocze wyjątki, nie pozostawiając łatwego sposobu debugowania, dlaczego obsada się nie powiodła) – ckarras

0

W obsadzie nie działa, ponieważ próbujesz rzucić od rodzaju object do interfejsu. Jeśli zamienić linię z elementami plastikowymi interfejsu:

IFrameworkClient fc = (IFrameworkClient)m_Client;

Będzie ona działać.

Alternatywnie jestem pewien, że można wykonać rzutowanie z obiektu na interfejs z operatorem as.

Zobacz ten artykuł uzyskać więcej informacji: http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx

One bardziej kawałek układanki. Interfejsy nie czerpią z object: http://blogs.msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx

+0

'm_Client' i' obj 'są prawie na pewno tym samym obiektem (chyba że zdefiniowana jest konwersja). Nie oczekuję, że to ma znaczenie ... –

+0

Nie ma. Mój test działa. – Will

10

Najbardziej prawdopodobną przyczyną jest to, że IFrameworkClient jest z innego zespołu w dwóch przypadkach, a zatem jest inny typ .NET. Nawet jeśli jest to ten sam kod, może to być inny typ.

Sprawdź AssemblyQualifiedName. Zauważ również, że jeśli ładujesz ten zestaw z odbiciem, możesz uzyskać inny typ nawet z tą samą nazwą AssemblyQualifiedName, dzięki kontekstowi ładowania.

+1

To była też moja pierwsza myśl. –

+0

To jedna z możliwości, zdecydowanie. Błędne odniesienie. Ale coś takiego zwykle działa podczas debugowania i nie działa po wdrożeniu (inny montaż w czasie wdrażania). Ilekroć to mi się przydarzyło, ponieważ Activator.CreateInstance nie aktywnie ładuje wszystkich złożeń powiązanych z typem, który on tworzy. – Will

+0

W moim przypadku ten sam zestaw został wdrożony w 2 różnych katalogach. Typ był ładowany dynamicznie w jednym miejscu i rzucany do interfejsu z drugiego zespołu. –

0

Jeśli klasa FPG.H60.AFF.TabControlH60 faktycznie implementuje IFrameworkClient, nie powinno być żadnego powodu, dla którego byłoby to niemożliwe. Jedyne, co mogę myśleć o tym, powoduje ten wyjątek, jeśli zbiór zawierający IFrameworkClient jest silnie nazwany, a obiekt Tab Control ma odniesienie do innej wersji zespołu zawierającego lub używasz innego interfejsu o nazwie IFrameworkClient.

3

Coś mi mówi Twój przykładowy kod opuszcza pewne rzeczy się ...

class Program 
{ 
    static void Main(string[] args) 
    { 
     var type = typeof(MyClass); 
     object obj = Activator.CreateInstance(type); 
     Type[] interfaces = obj.GetType().GetInterfaces(); 

     var m_Client = (UserControl)obj;   
     IFrameworkClient fc = (IFrameworkClient)obj; 
    } 
} 

public interface IFrameworkClient { } 

public class UserControl { } 

public class MyClass : UserControl, IFrameworkClient { } 

To kompiluje i działa.

Założę się, że biblioteka DLL zawierająca definicję IFrameworkClient nie została jeszcze załadowana przed rozpoczęciem rzutowania. Może się to zdarzyć, gdy używasz Activator.CreateInstance. Przed wysłaniem spróbuj wstawić var forceLoad = typeof(IFrameworkClient);.

3

Definiowanie IFrameworkClient interfejsu w niezależnej przestrzeni nazw (należy mieć nazw) niezależnego projektu (biblioteka klasa) .Następnie dodać refrence biblioteki klasy do kontroli projektu i główny projekt

+0

Dokładnie to, co zrobiłem i to działa. – broadband

28

I kapelusz te same problemy z Moja biblioteka zawierająca "plugin" -funkcjonalność ... W końcu działa ...

Oto mój problem: Miałem jeden główny zestaw przy użyciu wtyczek, jeden zespół z wtyczką (Plugin.dll) I (ważne) inny zestaw zapewniający funkcjonalność wtyczki (Library.dll).

Plugin.dll odniesione do głównego zespołu (w celu umożliwienia jego przedłużenie) i Library.dll z wtyczką-func. - pliki binarne trafiły do ​​katalogu "./Plugins" względem głównego zespołu.

Główny zespół odwoływał się również do wtyczki-func. montaż w celu użycia "PluginManager" jest napisany. Ten "PluginManager" pobiera ścieżkę i ładuje wszystkie pliki * .dll za pomocą odbicia, aby przeanalizować, czy istnieje interfejs "IPlugin" (który pochodzi również z Library.dll).

Everytime I nazwał PluginManager załadować wtyczki nie można oddanych im do „IPlugin”, choć ich wdrożenie go.

ja prawie wściekł - ale potem okazało się, cały problem. Kompilując wtyczkę, do katalogu "./Plugins" zapisano nie tylko "Plugin.dll", ale "Library.dll". Przez przypadkowe ładowanie "Library.dll" za każdym razem z moim PluginManager miałem teraz dwa typy "IPlugin" - jeden w rzeczywistym "Library.dll", który jest używany od głównego zespołu i który został załadowany przez mój PluginManager - i te były niekompatybilne!

Uwaga - jeśli po prostu nie ładujesz "./Plugins/Library.dll" napotkasz problem - ponieważ jeśli załadujesz "Plugin.dll", który odwołuje się do "Library.dll", to po prostu używa tego w ten sam katalog ... TILT ... !! Mój PluginManager usuwa teraz "Library.dll", gdzie go znajduje.

Kluczem jest: Należy upewnić się, że użytkownik nie korzysta dwa zespoły w różnych kontekstach!

+2

Ty, proszę pana, właśnie narobiłem mojego problemu, który przeszkadza mi od 4 godzin, po prostu odejdź. Wielkie dzięki! – beastofman

+0

Ta odpowiedź wymaga więcej uplayów! utknąłem przez wiele godzin ... – MattJ

+0

Bardzo pomocna odpowiedź, zaoszczędziła mi wiele czasu na podobny problem. Dzięki! –

1

Gdy Interface jest w innym zespole i dostaję moją klasę dynamicznie w run-time w innym zespole, interface casting będzie uznany za niesprawny jak próbkę (C# zna nasz interfejs jako innego typu niż których jedna klasa odziedziczone po tym).

To moja prosta i przydatna technika w tych przypadkach:

Kiedy jestem pewien, że mój Class odziedziczyła od wspomnianego Interface, więc piszę jedną magiczną linię (EQ IFrameworkClient). Kod tak:

dynamic fc = obj as IFrameworkClient ?? (dynamic) obj; 

Dzięki tej technice można:

  • Napisz swoje kody po tej linii kodu dla fc w design time bazy na Interface members informacji i vs systemu inteligencji Editor.
  • uniknięcia jakichkolwiek błędów odlewania interfejs w run-time

Uwagi:

  • Trzeba C# v4 używać dynamic type
  • Zazwyczaj nie lubię używać dynamic rodzaje kodów ale w moich może pomóc nam w niektórych przypadkach, takich jak ten
0

W moim przypadku musiałem dodać zdarzenie kompilacji, aby skopiować potrzebną bibliotekę DLL, ponieważ tworzyłem instancje i przypisywałem do typów interfejsu w czasie wykonywania. W przeciwnym razie załadowana biblioteka DLL może nie być najbardziej aktualną biblioteką DLL, a zatem może nie zostać przesłana do interfejsu.

Powodem, dla którego użyłem zdarzeń budowania w tym przypadku (zamiast dodawania biblioteki DLL jako odniesienia) jest to, że architektura jest taka, że ​​główna aplikacja powinna odwoływać się tylko do typów interfejsu, a wszystko inne powinno być ładowane dynamicznie.

TLDR; W przypadku dynamicznego ładowania typów z innej biblioteki DLL, należy skopiować najnowszą wersję tej biblioteki DLL do katalogu bin za pomocą zdarzeń kompilacji, w przeciwnym razie rzutowanie może nie działać, gdy wygląda na to, że powinna.

Powiązane problemy