Domanda

Prima di tutto, mi dispiace se questo è stato chiesto prima. Ho fatto una ricerca abbastanza completa e ho trovato niente di simile, ma forse ho perso qualcosa.

E ora alla domanda: sto cercando di invocare un costruttore attraverso la riflessione, senza fortuna. Fondamentalmente, ho un oggetto che voglio clonare, quindi guardo il costruttore di copia per il suo tipo e poi voglio invocarlo. Ecco quello che ho:

public Object clone(Object toClone) {
     MethodBase copyConstructor = type.GetConstructor(
         new Type[] { toClone.GetType() });
     return method.Invoke(toClone, new object[] { toClone }); //<-- doesn't work
}

io chiamo il metodo di cui sopra in questo modo:

List<int> list = new List<int>(new int[] { 0, 1, 2 });
List<int> clone = (List<int>) clone(list);

Ora, notate il metodo invoke che sto utilizzando è invoke di MethodBase. ConstructorInfo fornisce un metodo invoke che fa il lavoro, quando chiamato in questo modo:

return ((ConstructorInfo) method).Invoke(new object[] { toClone });

Tuttavia, voglio usare il metodo di MethodBase, perché in realtà invece di guardare il costruttore di copia ogni volta mi conservarlo in un dizionario, e il dizionario contiene entrambi i metodi e costruttori, quindi è un Dictionary<MethodBase>, non Dictionary<ConstructorInfo>. Potrei ovviamente cast ConstructorInfo come faccio io in precedenza, ma preferirei evitare la fusione e utilizzare il metodo MethodBase direttamente. Non riesco proprio a capire i giusti parametri.

Qualsiasi aiuto? Grazie mille.


Modifica
Benjamin,
Grazie mille per i vostri suggerimenti. Mi è stato effettivamente facendo esattamente quello che suggeriscono nel vostro secondo di modifica, ad eccezione (e questo è un grande "eccetto") il mio dizionario era dove

class ClonerMethod {

    public MethodBase method;
    public bool isConstructor;

    ...

    public Object invoke(Object toClone) {
        return isConstructor ?
            ((ConstructorInfo) method).Invoke(new object[] { toClone }) : //<-- I wanted to avoid this cast
            method.Invoke(toClone, null);
    }

}

E poi ho chiamato ClonerMethod di invoke su quello che ho trovato nel dizionario. non ho aggiunto il codice le offerte con tutto ciò che perché la risposta che cercavo era solo come chiamare Invoke su un ConstructorInfo con il metodo MethodBase di Invoke, quindi non volevo aggiungere informazioni inutili e troppo codice per voi ragazzi per leggere. Tuttavia, mi piace l'utilizzo del Func<,> molto molto meglio, quindi sto passando a quello. Anche facendo il metodo Clone generica è una bella aggiunta, ma nel mio caso il chiamante non conosce il tipo di oggetto, quindi mi tenerlo non generico, invece.

Non sapevo su Func<,>, e se sapessi che l'operatore lambda avevo dimenticato (non avevo davvero bisogno di qualcosa di simile prima), quindi in realtà ho imparato molto dalla risposta. Mi fa sempre piacere di imparare cose nuove, e questo verrà molto utile in futuro, quindi grazie mille! :)

È stato utile?

Soluzione

Se si sa che l'oggetto sta avendo un costruttore del genere, avete pensato di usare questo sovraccarico di Activator.CreateInstance invece?


Aggiornamento:. In modo da avere una ricerca a cascata per MethodInfo / MethodBase già e memorizzarli -> Se non si desidera / non possono utilizzare Activator

In questo caso non vedo un modo per fare ciò che si vuole, senza un cast. Ma - forse si potrebbe cambiare l'architettura per memorizzare un Dictionary<Type, Func<object, object>> e aggiungere quei casi Func<> invece. Rende il codice chiamante bello (presumo) e permetterebbe di fare questo cast una volta:

// Constructor
dictionary.Add(type,
  source => ((ConstructorInfo) method).Invoke(new object[] {source})
);

// Clone
dictionary.Add(type,
  source => method.Invoke(source, new object[]{})
);

In realtà, dal momento che vi interessa soltanto la differenza tra il costruttore e il metodo normale nel luogo stesso in cui li si afferra, si avrebbe non hanno bisogno di un cast a tutti, vero?

// Constructor 2
dictionary.Add(type,
  source => yourConstructorInfo.Invoke(new object[] {source})
);

A meno che non mi manca qualcosa (del tutto possibile, ovviamente) questo potrebbe risolvere il problema in questo modo, una volta sul lato definizione della recinzione e il chiamante non avrei bisogno di dispiacerebbe se questo è il costruttore o no?


Per l'ultima volta, poi ho intenzione di fermare la modifica spam. Ero annoiato e si avvicinò con il seguente codice. E 'questo che si sta cercando di realizzare?

public class Cloner {
    private readonly IDictionary<Type, Func<object, object>> _cloneMap =
            new Dictionary<Type, Func<object, object>>();

    public T Clone<T>(T source) {
        Type sourceType = source.GetType();
        Func<object, object> cloneFunc;

        if (_cloneMap.TryGetValue(sourceType, out cloneFunc)) {
            return (T)cloneFunc(source);
        }

        if (TryGetCopyConstructorCloneFunc(sourceType, out cloneFunc)) {
            _cloneMap.Add(sourceType, cloneFunc);
            return (T)cloneFunc(source);
        }

        if (TryGetICloneableCloneFunc(sourceType, out cloneFunc)) {
            _cloneMap.Add(sourceType, cloneFunc);
            return (T)cloneFunc(source);
        }

        return default(T);
    }

    private bool TryGetCopyConstructorCloneFunc(Type type, 
                    out Func<object, object> cloneFunc) {
        var constructor = type.GetConstructor(new[] { type });
        if (constructor == null) {
            cloneFunc = source => null;
            return false;
        }
        cloneFunc = source => constructor.Invoke(new[] { source });
        return true;
    }

    private bool TryGetICloneableCloneFunc(Type type,
                    out Func<object, object> cloneFunc) {
        bool isICloneable = typeof(ICloneable).IsAssignableFrom(type);
        var cloneMethod = type.GetMethod("Clone", new Type[] { });
        if (!isICloneable || (cloneMethod == null)) {
            cloneFunc = source => null;
            return false;
        }
        cloneFunc = source => cloneMethod.Invoke(source, new object[] {});
        return true;
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top