Domanda

Ho una fabbrica che dovrebbe creare oggetti che ereditano dalla classe Foo a run-time. Penserei che tipo di ritorno di System.Activator.CreateInstance era lo stesso come il tipo di un oggetto è la creazione, ma a giudicare dal seguente messaggio di errore, il suo tipo di ritorno è oggetto.

  

di errore 1 Impossibile convertire implicitamente il tipo di 'oggetto' a 'cs_sandbox.Foo'. Una conversione esplicita esiste (Vi manca un cast?) F: \ projects \ cs_sandbox \ Form1.cs 46 24 cs_sandbox

OK, forse I am manca un cast, ma

return (t)System.Activator.CreateInstance(t);

risultati in un altro messaggio di errore, che - devo ammettere - non ha senso per me:

  

di errore 1 Il tipo o dello spazio dei nomi il nome 't' non è stato trovato (che le manca un un riferimento all'assembly direttiva using o?) F: \ progetti \ cs_sandbox \ Form1.cs 45 25 cs_sandbox

Ed ecco il mio codice:

class Foo { }
class FooChild1 : Foo { }
class FooChild2 : Foo { }

class MyFactory
{
    public static Foo CreateInstance(string s)
    {
        Type t;
        if (s.StartsWith("abcdef"))
        {
            t = typeof(FooChild1);
            return System.Activator.CreateInstance(t);
        }
        else
        {
            t = typeof(FooChild2);
            return System.Activator.CreateInstance(t);
        }
    }
}

Come posso risolvere questo codice? Oppure, se non è risolvibile, quali sono gli altri modi di creare oggetti che ereditano da una classe specifica in fase di esecuzione?

È stato utile?

Soluzione

È necessario il cast dell'oggetto restituito al tipo Foo. Non ha senso per il cast a un tipo definito in una variabile. Dovrebbe essere noto dal compilatore, come il punto di lanciare attraverso la gerarchia di ereditarietà è soddisfacente controllo di tipo statico del compilatore.

return (Foo)System.Activator.CreateInstance(t);

C'è una versione generica, System.Activator.CreateInstance<T>, che crea un tipo noto (non una variabile di tipo, ma un argomento di tipo o di un tipo noto staticamente, in quest'ultimo caso, non ha molto senso però):

return System.Activator.CreateInstance<FooChild1>();

Altri suggerimenti

ho dovuto usare a scartare () metodo dopo aver attivato, come descritto a MSDN:

// Creates an instance of MyType defined in the assembly called ObjectHandleAssembly.
ObjectHandle obj = domain.CreateInstance("ObjectHandleAssembly", "MyType");

// Unwrapps the proxy to the MyType object created in the other AppDomain.
MyType testObj = (MyType)obj.Unwrap();

Come descritto su MSDN . Inoltre, ho dovuto utilizzare i parametri in questo modo:

    ObjectHandle obj = domain.CreateInstance("Other.Assembly.Name", "Full.Class.Namespace.ClassName");

Dopo aver cambiato il codice

Basta gettare i risultati a Foo come

return System.Activator.CreateInstance(t) as Foo;

o

return (Foo)System.Activator.CreateInstance(t);

Il primo è un po 'più robusto, perché non sarà possibile ottenere una deroga nel caso in cui cast non è possibile. Sarà semplicemente restituire null. Ma dipende da cosa si vuole.

Prima si è modificato il codice

Hai provato farmaci generici?

public static OutType CreateInstance<OutType>(string s)
{
    Type t;
    if (s.StartsWith("abcdef"))
    {
        t = typeof(Bar);
        return System.Activator.CreateInstance(t) as OutType;
    }
    else
    {
        t = typeof(Meh);
        return System.Activator.CreateInstance(t) as OutType;
    }
}

Ma voi avete un problema. Nel vostro metodo statico esistente che si sta tentando di restituire Bar e Meh che non sono correlate alla Foo in alcun modo. Questo sarà sempre un'eccezione a meno che il metodo restituisce anche un oggetto o un tipo antenato comune (come nel casting).

Per un controllo ancora più interna tipi si potrebbe definire più di un tipo generico che il metodo avrebbe utilizzato internamente.

Penso che probabilmente si dovrebbe fare questo:

public static Foo CreateInstance(string objectIdentifer)
{
   if (objectIdentifier == "Child1")
   {
      return (Foo)Activator.CreateInstance("Foo.FooChild1, FooChild1");
   }
   else
   {
      return (Foo)Activator.CreateInstance("Foo.FooChild1, FooChild2");
   }
}

Il mio punto è che in questo codice, il metodo CreateInstance ha alcun riferimento diretto al montaggio o complessi contenenti FooChild1 e FooChild2. Nel codice originale, si crea un tipo nominando esplicitamente FooChild1 e FooChild2, così si potrebbe anche solo loro una nuova invece di attivazione.

Ha senso per te?

Credo che la corretta è:

public static Foo CreateInstance(string objectIdentifer)
{
   if (objectIdentifier == "Child1")
   {
      return (Foo)Activator.CreateInstance(Type.GetType("Foo.FooChild1, FooChild1"));
   }
   else
   {
      return (Foo)Activator.CreateInstance(Type.GetType("Foo.FooChild1, FooChild2"));
   }
}

La speranza che può aiutare a

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top