Genel bir yöntemi çağırmak için yansımayı nasıl kullanabilirim?


1070

Tür parametresi derleme zamanında bilinmediğinde, bunun yerine çalışma zamanında dinamik olarak elde edildiğinde genel bir yöntemi çağırmanın en iyi yolu nedir?

Aşağıdaki örnek kodu göz önünde bulundurun - Example()yöntemin içinde, değişkende depolanan GenericMethod<T>()kullanarak çağırmanın en kısa yolu nedir?TypemyType

public class Sample
{
    public void Example(string typeName)
    {
        Type myType = FindType(typeName);

        // What goes here to call GenericMethod<T>()?
        GenericMethod<myType>(); // This doesn't work

        // What changes to call StaticMethod<T>()?
        Sample.StaticMethod<myType>(); // This also doesn't work
    }

    public void GenericMethod<T>()
    {
        // ...
    }

    public static void StaticMethod<T>()
    {
        //...
    }
}

7
Jon'un çözümünü denedim ve genel yöntemi sınıfımda herkese açık hale getirene kadar işe yaramadım. Başka bir Jon'un ciltleme bayraklarını belirtmeniz gerektiğini söyleyerek cevapladığını biliyorum ama bu yardımcı olmadı.
naskew

12
Ayrıca , özel / dahili yöntemi elde etmek için BindingFlags.Instancesadece ihtiyacınız değil BindingFlags.NonPublic.
Lars Kemmann

2
Bu sorunun modern versiyonu: stackoverflow.com/q/2433436/103167
Ben Voigt

@Peter Mortensen - fyi '?' Den önce boşluk kullandım İngilizce parçaları İngilizce olmayan (C #) parçalardan ayırmak; IMHO alanı kaldırmak onun gibi görünmesini sağlar? kodun bir parçasıdır. Hiçbir kod olmasaydı, kesinlikle boşlukları kaldırmayı kabul ederdim, ama bu durumda ...
Bevan

Yanıtlar:


1138

Yöntemi başlatmak için yansıma kullanmanız ve ardından MakeGenericMethod ile tür bağımsız değişkenleri sağlayarak "yapı" yapmanız gerekir :

MethodInfo method = typeof(Sample).GetMethod(nameof(Sample.GenericMethod));
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);

Statik bir yöntem nulliçin ilk argüman olarak iletin Invoke. Bu, jenerik yöntemlerle bir ilgisi yok - sadece normal yansıma.

Belirtildiği gibi, C # 4'ten itibaren bunun birçoğu daha basittir dynamic- tabii ki tür çıkarımını kullanabiliyorsanız. Sorudaki kesin örnek gibi, tür çıkarımının mevcut olmadığı durumlarda yardımcı olmaz.


92
+ 1; Not GetMethod()ihtiyaç duyabileceğiniz bu yüzden sadece, varsayılan olarak ortak örnek yöntemlerini dikkate alır BindingFlags.Staticve / veya BindingFlags.NonPublic.

20
Bayrakların doğru kombinasyonu BindingFlags.NonPublic | BindingFlags.Instance(ve isteğe bağlı olarak BindingFlags.Static).
Lars Kemmann

4
Bu sorudan iki kez işaretlenen bir soru, bunun statik yöntemlerle nasıl yapılacağını merak ediyor - ve teknik olarak burada soru da öyle. statik yöntemler çağrılırken generic.Invoke () öğesinin ilk parametresi null olmalıdır. İlk parametre yalnızca örnek yöntemleri çağrıldığında gereklidir.
Chris Moschini

2
@ChrisMoschini: Bunu cevaba ekledi.
Jon Skeet

2
@gzou: Cevaba bir şey ekledim - ancak sorudaki genel yöntemleri çağırmak için , dynamictür çıkarımı bulunmadığından yardımcı olmadığını unutmayın. (Derleyicinin tür argümanını belirlemek için kullanabileceği hiçbir argüman yoktur.)
Jon Skeet

170

Sadece orijinal cevaba ek olarak. Bu işe yarayacak olsa da:

MethodInfo method = typeof(Sample).GetMethod("GenericMethod");
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);

Derleme zamanı kontrolünü kaybetmeniz de biraz tehlikelidir GenericMethod. Daha sonra yeniden düzenleme ve yeniden adlandırma yaparsanız GenericMethod, bu kod fark etmez ve çalışma zamanında başarısız olur. Ayrıca, montajın herhangi bir son işlemesi varsa (örneğin, kullanılmayan yöntemleri / sınıfları gizlemek veya kaldırmak) bu kod da kırılabilir.

Derleme zamanında bağlanmakta olduğunuz yöntemi biliyorsanız, ve bu milyonlarca kez bu yüzden ek yük önemli değil, bu kodu olarak değiştirmek istiyorum:

Action<> GenMethod = GenericMethod<int>;  //change int by any base type 
                                          //accepted by GenericMethod
MethodInfo method = this.GetType().GetMethod(GenMethod.Method.Name);
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);

Çok hoş olmasa da, GenericMethodburada derleme zamanı referansınız vardır ve yeniden düzenleme yaparsanız, siler veya onunla bir şey yaparsanız GenericMethod, bu kod çalışmaya devam eder veya en azından derleme zamanında kırılır (örneğin kaldırırsanız GenericMethod).

Aynı şeyi yapmanın başka bir yolu da yeni bir sarmalayıcı sınıfı oluşturmak ve bunu oluşturmaktır Activator. Daha iyi bir yol olup olmadığını bilmiyorum.


5
Yansımanın bir yöntemi çağırmak için kullanıldığı durumlarda, yöntem adının kendisinin başka bir yöntemle bulunması normaldir. Yöntem adını önceden bilmek yaygın değildir.
Bevan

13
Düşünmenin yaygın kullanımlarını kabul ediyorum. Ancak asıl soru "GenericMethod <myType> ()" olarak nasıl çağrılacağıydı. Bu sözdizimine izin verildiyse, GetMethod () işlevine hiç ihtiyacımız olmayacaktı. Ama "GenericMethod <myType>" sorusu için? Bence cevap GenericMethod ile derleme zamanı bağlantısını kaybetmemek için bir yol içermelidir. Şimdi bu soru yaygınsa ya da bilmiyorum, ama Dün tam olarak bu problemi yaşadığımı biliyorum, ve bu yüzden bu soruya
girdim

20
Bunun GenMethod.Method.GetGenericMethodDefinition()yerine yapabilirsin this.GetType().GetMethod(GenMethod.Method.Name). Biraz daha temiz ve muhtemelen daha güvenlidir.
Daniel Cassidy

Örneğinizdeki "myType" ne anlama geliyor?
Geliştirici

37
Şimdi kullanabilirsiniznameof(GenericMethod)
dmigo

140

Yalnızca çalışma zamanında bilinen bir tür parametresiyle genel bir yöntemin çağrılması dynamic, yansıma API'si yerine bir tür kullanılarak büyük ölçüde basitleştirilebilir .

Bu tekniği kullanmak için türün gerçek nesneden bilinmesi gerekir (yalnızca Typesınıfın bir örneği değil ). Aksi takdirde, bu tür bir nesne oluşturmanız veya standart yansıma API çözümünü kullanmanız gerekir . Activator.CreateInstance yöntemini kullanarak bir nesne oluşturabilirsiniz .

Eğer genel bir yöntem çağırmak istiyorsanız, "normal" kullanımda türünü çıkarmış olurdu, o zaman sadece bilinmeyen tip nesnesi döküm geliyor dynamic. İşte bir örnek:

class Alpha { }
class Beta { }
class Service
{
    public void Process<T>(T item)
    {
        Console.WriteLine("item.GetType(): " + item.GetType()
                          + "\ttypeof(T): " + typeof(T));
    }
}

class Program
{
    static void Main(string[] args)
    {
        var a = new Alpha();
        var b = new Beta();

        var service = new Service();
        service.Process(a); // Same as "service.Process<Alpha>(a)"
        service.Process(b); // Same as "service.Process<Beta>(b)"

        var objects = new object[] { a, b };
        foreach (var o in objects)
        {
            service.Process(o); // Same as "service.Process<object>(o)"
        }
        foreach (var o in objects)
        {
            dynamic dynObj = o;
            service.Process(dynObj); // Or write "service.Process((dynamic)o)"
        }
    }
}

Ve işte bu programın çıktısı:

item.GetType(): Alpha    typeof(T): Alpha
item.GetType(): Beta     typeof(T): Beta
item.GetType(): Alpha    typeof(T): System.Object
item.GetType(): Beta     typeof(T): System.Object
item.GetType(): Alpha    typeof(T): Alpha
item.GetType(): Beta     typeof(T): Beta

Processiletilen bağımsız değişkenin gerçek türünü ( GetType()yöntemi kullanarak ) ve genel parametrenin türünü ( typeofişleç kullanarak ) yazan genel bir örnek yöntemidir .

Nesne bağımsız değişkenini dynamictür yazarak, çalışma zamanına kadar type parametresini sağlamayı erteledik. Ne zaman Processmetot ile çağrılır dynamicargüman sonra derleyici bu argüman türü hakkında umursamıyor. Derleyici, çalışma zamanında gerçekte aktarılan argüman türlerini (yansıma kullanarak) kontrol eden ve çağrılacak en iyi yöntemi seçen kod üretir. Burada sadece bir genel yöntem var, bu yüzden uygun bir tür parametresiyle çağrıldı.

Bu örnekte, çıktı sizin yazdığınız gibidir:

foreach (var o in objects)
{
    MethodInfo method = typeof(Service).GetMethod("Process");
    MethodInfo generic = method.MakeGenericMethod(o.GetType());
    generic.Invoke(service, new object[] { o });
}

Dinamik tipte versiyon kesinlikle daha kısa ve yazımı daha kolaydır. Ayrıca, bu işlevi birden çok kez çağırmanın performansı hakkında endişelenmemelisiniz. DLR'deki önbellek mekanizması sayesinde aynı türden argümanlarla bir sonraki çağrı daha hızlı olmalıdır . Tabii ki, çağrılan delegeleri önbelleğe alan bir kod yazabilirsiniz, ancak dynamictürü kullanarak bu davranışı ücretsiz olarak alabilirsiniz.

Aramak istediğiniz genel yöntemin parametreli bir türden bağımsız değişkeni yoksa (bu nedenle tür parametresi çıkartılamaz), aşağıdaki yöntemdeki gibi bir yardımcı yöntemde genel yöntemin çağrılmasını sarabilirsiniz:

class Program
{
    static void Main(string[] args)
    {
        object obj = new Alpha();

        Helper((dynamic)obj);
    }

    public static void Helper<T>(T obj)
    {
        GenericMethod<T>();
    }

    public static void GenericMethod<T>()
    {
        Console.WriteLine("GenericMethod<" + typeof(T) + ">");
    }
}

Artan tip güvenliği

dynamicNesneyi yansıma API'sini kullanmak yerine kullanmakla ilgili gerçekten harika olan şey, yalnızca çalışma zamanına kadar bilmediğiniz bu türün derleme zamanı denetimini kaybetmenizdir. Diğer argümanlar ve yöntemin adı derleyici tarafından her zamanki gibi statik olarak analiz edilir. Daha fazla bağımsız değişken kaldırır veya eklerseniz, türlerini değiştirin veya yöntem adını yeniden adlandırın, ardından derleme zamanı hatası alırsınız. Yöntem adını bir dize olarak Type.GetMethodve bağımsız değişkenleri nesneler dizisi olarak sağlarsanız bu gerçekleşmez MethodInfo.Invoke.

Aşağıda, derleme zamanında (yorumlanmış kod) ve çalışma zamanında bazı hataların nasıl yakalanabileceğini gösteren basit bir örnek verilmiştir. Ayrıca, DLR'nin hangi yöntemi çağıracağını nasıl çözmeye çalıştığını da gösterir.

interface IItem { }
class FooItem : IItem { }
class BarItem : IItem { }
class Alpha { }

class Program
{
    static void Main(string[] args)
    {
        var objects = new object[] { new FooItem(), new BarItem(), new Alpha() };
        for (int i = 0; i < objects.Length; i++)
        {
            ProcessItem((dynamic)objects[i], "test" + i, i);

            //ProcesItm((dynamic)objects[i], "test" + i, i);
            //compiler error: The name 'ProcesItm' does not
            //exist in the current context

            //ProcessItem((dynamic)objects[i], "test" + i);
            //error: No overload for method 'ProcessItem' takes 2 arguments
        }
    }

    static string ProcessItem<T>(T item, string text, int number)
        where T : IItem
    {
        Console.WriteLine("Generic ProcessItem<{0}>, text {1}, number:{2}",
                          typeof(T), text, number);
        return "OK";
    }
    static void ProcessItem(BarItem item, string text, int number)
    {
        Console.WriteLine("ProcessItem with Bar, " + text + ", " + number);
    }
}

Burada yine argümanı dynamictüre çevirerek bir yöntem uygularız . Yalnızca ilk bağımsız değişkenin türünün doğrulanması çalışma zamanına ertelenir. Aradığınız yöntemin adı yoksa veya başka bağımsız değişkenler geçersizse (yanlış sayıda bağımsız değişken veya yanlış tür) bir derleyici hatası alırsınız.

Sınavı geçtikten sonra dynamicbir yönteme argüman sonra bu çağrı olduğunu son zamanlarda bağlanmış . Yöntem aşırı yük çözünürlüğü çalışma zamanında gerçekleşir ve en iyi aşırı yükü seçmeye çalışır. Bu nedenle, ProcessItemyöntemi bir tür nesneyle BarItemçağırırsanız, genel olmayan yöntemi çağıracaksınız, çünkü bu tür için daha iyi bir eşleşmedir. Ancak, Alphabu nesneyi işleyebilecek bir yöntem olmadığından türün bir argümanını ilettiğinizde bir çalışma zamanı hatası alırsınız (genel bir yöntem kısıtlamaya sahiptir where T : IItemve Alphasınıf bu arabirimi uygulamaz). Ama bütün mesele bu. Derleyicide bu çağrının geçerli olduğu bilgisi yok. Bir programcı olarak bunu biliyorsunuz ve bu kodun hatasız çalıştığından emin olmalısınız.

Dönüş türü gotcha

Dinamik türünün bir parametresi olmayan bir boşluk yöntemini çağırarak bittiğinde, döndürme türü muhtemelen olacaktır olmak dynamicçok . Dolayısıyla, önceki örneği bu kodla değiştirirseniz:

var result = ProcessItem((dynamic)testObjects[i], "test" + i, i);

sonuç nesnesinin türü olur dynamic. Bunun nedeni derleyicinin hangi yöntemin çağrıldığını her zaman bilmemesidir. İşlev çağrısının dönüş türünü biliyorsanız , kodun geri kalanı statik olarak yazılması için bunu örtük olarak gerekli türe dönüştürmelisiniz :

string result = ProcessItem((dynamic)testObjects[i], "test" + i, i);

Tür eşleşmezse bir çalışma zamanı hatası alırsınız.

Aslında, önceki örnekte sonuç değerini almaya çalışırsanız, ikinci döngü yinelemesinde bir çalışma zamanı hatası alırsınız. Bunun nedeni, bir void işlevinin dönüş değerini kaydetmeye çalışmanızdır.


Mariusz, tarafından karıştırıldı "Ancak, bu nesneyi işleyebilecek bir yöntem olmadığı için Alpha türü argümanını ilettiğinizde çalışma zamanı hatası alırsınız." Var a = new Alpha () ProcessItem (a, "test" + i , i) Jenerik ProcessItem yöntemi neden "Genel İşlem Öğesi" çıktısı vererek bunu etkili bir şekilde ele almıyor?
Alex Edelstein

@AlexEdelstein Cevabımı biraz açıklığa kavuşturmak için düzenledim. Bunun nedeni, jenerik ProcessItemyöntemin genel bir kısıtlamaya sahip olması ve yalnızca IItemarabirimi uygulayan nesneyi kabul etmesidir. Ne zaman arayacağınız ProcessItem(new Aplha(), "test" , 1);ya da ProcessItem((object)(new Aplha()), "test" , 1);bir derleyici hatası alacaksınız, ancak yayın yaparken dynamicbu kontrolü çalışma zamanına erteleyin.
Mariusz Pawelski

Harika cevap ve açıklama, benim için mükemmel çalışıyor. Kabul edilen cevaptan çok daha iyi, yazması daha kısa, daha performanslı ve daha güvenli.
ygoe

17

C # 4.0 ile, DLR çalışma zamanı türlerini kullanarak arayabileceği için yansıma gerekli değildir. DLR kitaplığını kullanmak dinamik olarak bir acı oluşturduğundan (C # derleyicisi sizin için kod üretme yerine), açık kaynak çerçevesi Dynamitey (.net standart 1.5), derleyicinin oluşturduğu aynı çağrılara kolay önbellekli çalışma zamanı erişimi sağlar senin için.

var name = InvokeMemberName.Create;
Dynamic.InvokeMemberAction(this, name("GenericMethod", new[]{myType}));


var staticContext = InvokeContext.CreateStatic;
Dynamic.InvokeMemberAction(staticContext(typeof(Sample)), name("StaticMethod", new[]{myType}));

13

Adrian Gallero'nun cevabına ekleme :

Tür bilgisinden genel bir yöntemin çağrılması üç adımdan oluşur.

TLDR: Bilinen bir genel yöntemin bir tür nesnesiyle çağrılması şu şekilde yapılabilir:

((Action)GenericMethod<object>)
    .Method
    .GetGenericMethodDefinition()
    .MakeGenericMethod(typeof(string))
    .Invoke(this, null);

burada GenericMethod<object>çağrılacak yöntem adı ve genel kısıtlamaları karşılayan her türdür.

(Eylem), çağrılacak yöntemin imzasıyla eşleşir, yani ( Func<string,string,int>veya Action<bool>)

Adım 1 genel yöntem tanımı için MethodInfo alıyor

Yöntem 1: GetMethod () veya GetMethods () yöntemini uygun türler veya bağlayıcı bayraklarla kullanın.

MethodInfo method = typeof(Sample).GetMethod("GenericMethod");

Yöntem 2: Bir temsilci oluşturun, MethodInfo nesnesini alın ve GetGenericMethodDefinition'ı çağırın

Yöntemleri içeren sınıfın içinden:

MethodInfo method = ((Action)GenericMethod<object>)
    .Method
    .GetGenericMethodDefinition();

MethodInfo method = ((Action)StaticMethod<object>)
    .Method
    .GetGenericMethodDefinition();

Yöntemleri içeren sınıfın dışından:

MethodInfo method = ((Action)(new Sample())
    .GenericMethod<object>)
    .Method
    .GetGenericMethodDefinition();

MethodInfo method = ((Action)Sample.StaticMethod<object>)
    .Method
    .GetGenericMethodDefinition();

C # 'da, bir yöntemin adı, yani "ToString" veya "GenericMethod" aslında bir veya daha fazla yöntem içerebilen bir grup yöntemi ifade eder. Yöntem parametresi türlerini sağlayana kadar, hangi yönteme başvurduğunuz bilinmemektedir.

((Action)GenericMethod<object>)Belirli bir yöntem için delege anlamına gelir. ((Func<string, int>)GenericMethod<object>) "GenericMethod" un farklı aşırı yüklenmesine işaret eder

Yöntem 3: Yöntem çağrısı ifadesi içeren bir lambda ifadesi oluşturun, MethodInfo nesnesini ve ardından GetGenericMethodDefinition'ı edinin

MethodInfo method = ((MethodCallExpression)((Expression<Action<Sample>>)(
    (Sample v) => v.GenericMethod<object>()
    )).Body).Method.GetGenericMethodDefinition();

Bu,

Vücudun istediğiniz yöntemi çağırdığı bir lambda ifadesi oluşturun.

Expression<Action<Sample>> expr = (Sample v) => v.GenericMethod<object>();

Gövdeyi çıkarın ve MethodCallExpression'a yayınlayın

MethodCallExpression methodCallExpr = (MethodCallExpression)expr.Body;

Yöntemden genel yöntem tanımını alın

MethodInfo methodA = methodCallExpr.Method.GetGenericMethodDefinition();

Adım 2 uygun tür (ler) ile genel bir yöntem oluşturmak için MakeGenericMethod çağırıyor.

MethodInfo generic = method.MakeGenericMethod(myType);

Adım 3 yöntemi uygun argümanlarla çağırıyor.

generic.Invoke(this, null);

8

Kimse " klasik Yansıma " çözümünü sunmadı , bu yüzden tam bir kod örneği:

using System;
using System.Collections;
using System.Collections.Generic;

namespace DictionaryRuntime
{
    public class DynamicDictionaryFactory
    {
        /// <summary>
        /// Factory to create dynamically a generic Dictionary.
        /// </summary>
        public IDictionary CreateDynamicGenericInstance(Type keyType, Type valueType)
        {
            //Creating the Dictionary.
            Type typeDict = typeof(Dictionary<,>);

            //Creating KeyValue Type for Dictionary.
            Type[] typeArgs = { keyType, valueType };

            //Passing the Type and create Dictionary Type.
            Type genericType = typeDict.MakeGenericType(typeArgs);

            //Creating Instance for Dictionary<K,T>.
            IDictionary d = Activator.CreateInstance(genericType) as IDictionary;

            return d;

        }
    }
}

Yukarıdaki DynamicDictionaryFactorysınıfın bir yöntemi var

CreateDynamicGenericInstance(Type keyType, Type valueType)

ve yarattığı ve bir ıdictionary örneğini döndürür, kimin anahtarları ve değerleri tam olarak çağrı belirtilen çeşitleri keyTypeve valueType.

Aşağıda, bu yöntemi bir örnek oluşturmak ve kullanmak için nasıl çağıracağınıza dair eksiksiz bir örnek verilmiştirDictionary<String, int> :

using System;
using System.Collections.Generic;

namespace DynamicDictionary
{
    class Test
    {
        static void Main(string[] args)
        {
            var factory = new DictionaryRuntime.DynamicDictionaryFactory();
            var dict = factory.CreateDynamicGenericInstance(typeof(String), typeof(int));

            var typedDict = dict as Dictionary<String, int>;

            if (typedDict != null)
            {
                Console.WriteLine("Dictionary<String, int>");

                typedDict.Add("One", 1);
                typedDict.Add("Two", 2);
                typedDict.Add("Three", 3);

                foreach(var kvp in typedDict)
                {
                    Console.WriteLine("\"" + kvp.Key + "\": " + kvp.Value);
                }
            }
            else
                Console.WriteLine("null");
        }
    }
}

Yukarıdaki konsol uygulaması yürütüldüğünde, doğru ve beklenen sonucu alırız:

Dictionary<String, int>
"One": 1
"Two": 2
"Three": 3

2

Bu, Grax'in cevabına dayanan 2 sentim , ancak genel bir yöntem için iki parametre gerekli.

Yönteminizin bir Helpers sınıfında aşağıdaki gibi tanımlandığını varsayın:

public class Helpers
{
    public static U ConvertCsvDataToCollection<U, T>(string csvData)
    where U : ObservableCollection<T>
    {
      //transform code here
    }
}

Benim durumumda, U tipi her zaman T tipinde gözlemlenebilir bir koleksiyon saklama nesnesidir.

Türlerimi önceden tanımladığım için, öncelikle gözlemlenebilir koleksiyonu (U) ve içinde depolanan nesneyi (T) temsil eden "" kukla "nesneleri oluşturuyorum ve aşağıda Make'ı çağırırken türlerini almak için kullanılacak

object myCollection = Activator.CreateInstance(collectionType);
object myoObject = Activator.CreateInstance(objectType);

Ardından Genel işlevinizi bulmak için GetMethod'u arayın:

MethodInfo method = typeof(Helpers).
GetMethod("ConvertCsvDataToCollection");

Şimdiye kadar, yukarıdaki çağrı yukarıda açıklananla hemen hemen aynıdır, ancak birden fazla parametre iletmeniz gerektiğinde küçük bir farkla.

Yukarıda oluşturulan "kukla" nesneler 'türlerini içeren MakeGenericMethod işlevine bir Type [] dizisi iletmeniz gerekir:

MethodInfo generic = method.MakeGenericMethod(
new Type[] {
   myCollection.GetType(),
   myObject.GetType()
});

Bu yapıldıktan sonra, yukarıda belirtildiği gibi Çağırma yöntemini çağırmanız gerekir.

generic.Invoke(null, new object[] { csvData });

Ve işiniz bitti. Bir cazibe çalışır!

GÜNCELLEME:

@Bevan vurgulandığı gibi, params alır gibi MakeGenericMethod işlevini çağırırken bir dizi oluşturmak gerek yok ve ben sadece doğrudan bu işleve türleri geçebilir gibi türleri almak için bir nesne oluşturmak gerekmez. Benim durumumda, ben başka bir sınıfta önceden tanımlanmış türleri olduğundan, sadece kodumu şöyle değiştirdi:

object myCollection = null;

MethodInfo method = typeof(Helpers).
GetMethod("ConvertCsvDataToCollection");

MethodInfo generic = method.MakeGenericMethod(
   myClassInfo.CollectionType,
   myClassInfo.ObjectType
);

myCollection = generic.Invoke(null, new object[] { csvData });

myClassInfo, yapıcıya Typeiletilen bir enum değerine dayalı olarak çalışma zamanında ayarladığım 2 özellik içerir ve bana daha sonra MakeGenericMethod'da kullanacağım ilgili türleri sağlar.

Bu @Bevan'ı vurguladığınız için tekrar teşekkür ederiz.


Params anahtar sözcüğüne MakeGenericMethod()sahip argümanlar, böylece bir dizi oluşturmanız gerekmez; ne de türleri elde etmek için örnekler oluşturmanız gerekmez - yeterli olacaktır. methodInfo.MakeGenericMethod(typeof(TCollection), typeof(TObject))
Bevan

0

Enigmativity'nin cevabından esinlenerek - iki (veya daha fazla) sınıfınız olduğunu varsayalım.

public class Bar { }
public class Square { }

ve yöntemi, Foo<T>ile bildirilen Barve ile çağırmak istersiniz.Square

public class myClass
{
    public void Foo<T>(T item)
    {
        Console.WriteLine(typeof(T).Name);
    }
}

Ardından aşağıdaki gibi bir Uzantı yöntemi uygulayabilirsiniz :

public static class Extension
{
    public static void InvokeFoo<T>(this T t)
    {
        var fooMethod = typeof(myClass).GetMethod("Foo");
        var tType = typeof(T);
        var fooTMethod = fooMethod.MakeGenericMethod(new[] { tType });
        fooTMethod.Invoke(new myClass(), new object[] { t });
    }
}

Bununla, basitçe şöyle çağırabilirsiniz Foo:

var objSquare = new Square();
objSquare.InvokeFoo();

var objBar = new Bar();
objBar.InvokeFoo();

her sınıf için çalışıyor. Bu durumda, çıktı verecektir:

Kare
Çubuk

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.