Rzutowanie na implementowany interfejs

0

Nie wiem co się dzieje... Tworzę sobie aplikację z obsługą wtyczek na bazie pewnego tutoriala. W nim wtyczka musi implementować interfejs IPlugin, u mnie się to nazywa IThetysPlugin.

Dodawanie wtyczki i jej ładowanie wygląda tak:

//Create a new assembly from the plugin file we're adding..
            Assembly pluginAssembly = Assembly.LoadFrom(FileName);

            //Next we'll loop through all the Types found in the assembly
            foreach (Type pluginType in pluginAssembly.GetTypes())
            {
                if (pluginType.IsPublic) //Only look at public types
                {
                    if (!pluginType.IsAbstract)  //Only look at non-abstract types
                    {
                        //Gets a type object of the interface we need the plugins to match
                        Type typeInterface = pluginType.GetInterface("IThetysPlugin", true);

                        //Make sure the interface we want to use actually exists
                        if (typeInterface != null)
                        {
                            //Create a new available plugin since the type implements the IPlugin interface
                            Types.AvailablePlugin newPlugin = new Types.AvailablePlugin();

                            //Set the filename where we found it
                            newPlugin.AssemblyPath = FileName;

                            //Create a new instance and store the instance in the collection for later use
                            //We could change this later on to not load an instance.. we have 2 options
                            //1- Make one instance, and use it whenever we need it.. it's always there
                            //2- Don't make an instance, and instead make an instance whenever we use it, then close it
                            //For now we'll just make an instance of all the plugins
                            newPlugin.Instance = (IThetysPlugin)Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));

                            //Set the Plugin's host to this class which inherited IPluginHost
                            newPlugin.Instance.Host = this;
(...)

Wywraca się na rzutowaniu Activator.CreateInstance na IThetysPlugin twierdząc, że "Unable to cast". Czyżby nie dało się rzutować klasy implementującej interfejs na tenże interfejs? Dlaczego?

Sama wtyczka, którą skompilowaną do postaci DLL próbuję załadować wygląda tak:

namespace ClassicSkinLoader
{
    public class ClassicSkinLoader : IThetysPlugin
    {
        public ClassicSkinLoader()
		{
			
		}
		
		//Declarations of all our internal plugin variables
		string myName = "Classic Skin Loader Plugin";
		string myDescription = "Wtyczka do ładowania klasycznych skórek programu PilotMP3";
		string myAuthor = "Marcin \"Ktos \" Badurowicz";
		string myVersion = "1.0.0";

		IPluginHost myHost = null;
		
        System.Windows.Forms.UserControl myMainInterface = new Cocpit();
		
		/// <summary>
		/// Description of the Plugin's purpose
		/// </summary>
		public string Description
		{
			get {return myDescription;}
		}

		/// <summary>
		/// Author of the plugin
		/// </summary>
		public string Author
		{
			get	{return myAuthor;}
		
		}

(... tutaj reszta rzeczy, które musi implementować coś co dziedziczy po IThetysPlugin)

Ktoś ma jakiś pomysł dlaczego to nie działa? Większość rzeczy kopiowałem ze wspomnianego tutoriala, jedynie co najwyżej zmieniając właśnie np. nazwę typu wtyczki. W przykładowym pliku ichnim - działa.

0

Też probuję z tym walczyć. Nie wiem tylko po co szukasz publicznych klas, skoro główna aplikacja i tak nie będzie wiedziała jak je wykorzystać. Aplikacja będzie wiedziała tylko o metodach zawartych w Interfejsie IThetysPlugin, właściwie tylko o nich powinna wiedzieć. Reszta jej nie powinna interesować. Jeśli rozwiązałeś problem z rzutowaniem na Interfejsem, napisz :)

0

A jaka jest dokladnie tresc bledu? Pisze, ze czego nie moze zrzutowac?

//edit
Poza tym czemu nie zrobisz

newPlugin.Instance = (IThetysPlugin)Activator.CreateInstance(pluginType);

skoro pluginType jest obiektem typu Type (ale lyso brzmi :P )

0

"Nie można rzutować obiektu typu [tu typ klasy] na typ [tu typ interfejsu]."

Object obj = (IModule)a.CreateInstance("UsersModule.UsersModule");
(obj as IModule).InitializeModule(null); //to metoda, którą posiada każdy plugin.

UsersModule to klasa w dll w przestrzeni nazw o tej samej nazwie, która implementuje IModule.

0

Rozumiem, ze deklaracja interfejsu znajduje sie w dll'ce, tak? Czy w samej aplikacji tez?
<nie jestem="jestem" pewien="pewien">
Z tego co pamietam, ja kiedys mialem problem, bo mialem deklaracje interfejsu w assembly (zeby dalo sie go implementowac) i w aplikacji (zeby mozna bylo na niego rzutowac). Ale to nie dzialalo, bo program uznawal oba interfejsy za rozne.
</nie jestem pewien>
Zrobilem to w koncu przez refleksje, ale jak to musze rzucic okiem w kod (znaczy najpierw go znalezc ;) )

0

Interfejs jest i w Pluginie i Aplikacji, jedyna różnica jaka jest to inne przestrzenie nazw, może tu jest problem i kompilator uznaje to za rożne typy, chociaż to są takie same...

Na razie probuje ściągnąć przykład z http://www.codeproject.com/KB/cs/c__plugin_architecture.aspx, ale nie mogę dostać maila z potwierdzeniem rejestracji :P

0

Jezeli sa w innych przestrzeniach to na 99% kompilator uznaje je za rozne (w koncu po to sa przestrzenie).

0

Właśnie chyba o to chodzi. Zamiast dodać dependences dodałem interfejs do pluginu jako normalny plik.

0

Ja mialem takie cudo do ladowania dllki:

w assembly.dll jest definicja IInterface, oprocz tego klasa InterfaceFactory:

namespace Interface.Loader
{
	public class InterfaceFactory: MarshalByRefObject
	{
		private const BindingFlags fBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;

		public InterfaceFactory() {}

		public IInterface Create( string assemblyFile, string typeName, object[] constructArgs )
		{
			return (IInterface) Activator.CreateInstanceFrom(
				assemblyFile, typeName, false, fBindingFlags, null, constructArgs,
				null, null, null ).Unwrap();
		}
	}
}

W kodzie wlasciwym:

		public static IInterface Load(String iDllName, String iFullClassName)
		{
			ApplicationDomain = AppDomain.CreateDomain("SecondaryDomain");
			InterfaceFactory vFactory = (InterfaceFactory) ApplicationDomain.CreateInstance("assembly", "Interface.Loader.InterfaceFactory" ).Unwrap();
			IInterface vInterface = vFactory.Create( iDllName, iFullClassName, new object[] {});
			return vInterface;
		}

U mnie chodzilo glownie o mozliwosc usuniecia dll z pamieci (stad osobne AppDomain), zeby dalo sie ja zaktualizowac z netu w trakcie dzialania programu.

0

Pozmieniałem trochę z przestaniami nazw, Interfejs dałem do oddzielnego projektu i dołączyłem do aplikacji i pluginu przez References i poszło :)

Assembly a = Assembly.LoadF2om(@"C:\htdocs\widecms\Modules\UsersModule\bin\Debug\UsersModule.dll");
Type type = a.GetType("UsersModule.UsersModule");
IModule m = (IModule)Activator.CreateInstance(type);
0

Miło się dowiedzieć, bo ja ten temat zostawiłem już jakiś czas temu ;-)

1 użytkowników online, w tym zalogowanych: 0, gości: 1