Yansıma: Yöntemle Parametreleri Çağırma


197

Parametreleri ile yansıma yoluyla bir yöntemi çağırmaya çalışıyorum ve elde:

nesne hedef türüyle eşleşmiyor

Parametresiz bir yöntem çağırırsam iyi çalışır. Yöntemi çağırırsanız aşağıdaki kod dayanarak Test("TestNoParameters"), iyi çalışıyor. Ancak Test("Run")ararsam bir istisna alırım. Kodumda bir sorun mu var?

Benim ilk amacım nesnelerin bir dizi geçmek oldu public void Run(object[] options)ama bu işe yaramadı ve daha basit bir şey denedim, örneğin dize başarı olmadan.

// Assembly1.dll
namespace TestAssembly
{
    public class Main
    {
        public void Run(string parameters)
        { 
            // Do something... 
        }
        public void TestNoParameters()
        {
            // Do something... 
        }
    }
}

// Executing Assembly.exe
public class TestReflection
{
    public void Test(string methodName)
    {
        Assembly assembly = Assembly.LoadFile("...Assembly1.dll");
        Type type = assembly.GetType("TestAssembly.Main");

        if (type != null)
        {
            MethodInfo methodInfo = type.GetMethod(methodName);

            if (methodInfo != null)
            {
                object result = null;
                ParameterInfo[] parameters = methodInfo.GetParameters();
                object classInstance = Activator.CreateInstance(type, null);

                if (parameters.Length == 0)
                {
                    // This works fine
                    result = methodInfo.Invoke(classInstance, null);
                }
                else
                {
                    object[] parametersArray = new object[] { "Hello" };

                    // The invoke does NOT work;
                    // it throws "Object does not match target type"             
                    result = methodInfo.Invoke(methodInfo, parametersArray);
                }
            }
        }
    }
}

4
doğru satır object [] parametersArray = new object [] {new object [] {"Merhaba"}};
Nick Kovalsky

Yanıtlar:


236

Null parametre dizisiyle yapılan çağrıda olduğu gibi, "methodInfo" öğesini "classInstance" olarak değiştirin.

  result = methodInfo.Invoke(classInstance, parametersArray);

Bu, uzak bir montaj örneğiyle çalışırken dışında çalışır. Sorun çok yararlı olmayan aynı hatayı dışarı dökülmesiydi. Bunu düzeltmek için birkaç saat geçirdim ve hem davam hem de burada sağlananlara yeni bir genel çözüm gönderdim. Herkes ihtiyaç duyabilir :)
Martin Kool

4
parametreler birden fazla tipteyse dizi nasıl olmalıdır? bir dizi nesne ??
Radu Vlad

Evet, argümanlarda birden fazla tür olması bir nesne [] olmalıdır
Martin Johansson

29

Orada bir böceğin var

result = methodInfo.Invoke(methodInfo, parametersArray);

olmalı

result = methodInfo.Invoke(classInstance, parametersArray);

24

Temel bir hata burada:

result = methodInfo.Invoke(methodInfo, parametersArray); 

Yöntemi bir örneğinde çağırıyorsunuz MethodInfo. Çağırmak istediğiniz nesne türünün bir örneğini iletmeniz gerekir.

result = methodInfo.Invoke(classInstance, parametersArray);

11

Sağlanan çözüm, uzak montajdan yüklenen tür örnekleri için çalışmaz. Bunu yapmak için, CreateInstance çağrısı ile döndürülen türün açık bir tür yeniden eşlemesini içeren tüm durumlarda çalışan bir çözüm.

Uzak bir derlemede bulunduğu gibi benim classInstance oluşturmak için böyle gerekir.

// sample of my CreateInstance call with an explicit assembly reference
object classInstance = Activator.CreateInstance(assemblyName, type.FullName); 

Ancak, yukarıda verilen cevapla bile aynı hatayı alırsınız. İşte nasıl gideceğiniz:

// first, create a handle instead of the actual object
ObjectHandle classInstanceHandle = Activator.CreateInstance(assemblyName, type.FullName);
// unwrap the real slim-shady
object classInstance = classInstanceHandle.Unwrap(); 
// re-map the type to that of the object we retrieved
type = classInstace.GetType(); 

Ardından, burada belirtilen diğer kullanıcılar gibi yapın.


5

Bunu şöyle kullanırdım, yolu daha kısa ve herhangi bir sorun yaratmayacak

        dynamic result = null;
        if (methodInfo != null)
        {
            ParameterInfo[] parameters = methodInfo.GetParameters();
            object classInstance = Activator.CreateInstance(type, null);
            result = methodInfo.Invoke(classInstance, parameters.Length == 0 ? null : parametersArray);
        }

3
 Assembly assembly = Assembly.LoadFile(@"....bin\Debug\TestCases.dll");
       //get all types
        var testTypes = from t in assembly.GetTypes()
                        let attributes = t.GetCustomAttributes(typeof(NUnit.Framework.TestFixtureAttribute), true)
                        where attributes != null && attributes.Length > 0
                        orderby t.Name
                        select t;

        foreach (var type in testTypes)
        {
            //get test method in types.
            var testMethods = from m in type.GetMethods()
                              let attributes = m.GetCustomAttributes(typeof(NUnit.Framework.TestAttribute), true)
                              where attributes != null && attributes.Length > 0
                              orderby m.Name
                              select m;

            foreach (var method in testMethods)
            {
                MethodInfo methodInfo = type.GetMethod(method.Name);

                if (methodInfo != null)
                {
                    object result = null;
                    ParameterInfo[] parameters = methodInfo.GetParameters();
                    object classInstance = Activator.CreateInstance(type, null);

                    if (parameters.Length == 0)
                    {
                        // This works fine
                        result = methodInfo.Invoke(classInstance, null);
                    }
                    else
                    {
                        object[] parametersArray = new object[] { "Hello" };

                        // The invoke does NOT work;
                        // it throws "Object does not match target type"             
                        result = methodInfo.Invoke(classInstance, parametersArray);
                    }
                }

            }
        }

3

Yukarıda önerilen tüm cevaplarla çalışmaya çalıştım ama hiçbir şey benim için işe yaramıyor gibi görünüyor. Burada benim için neyin işe yaradığını anlatmaya çalışıyorum.

Eğer gibi bazı yöntemini çağırarak eğer inanıyorum Mainaltında veya hatta söz konusu gibi tek bir parametre ile, sadece gelen parametrenin türünü değiştirmek zorunda stringiçin objectçalışmalarına bunun için. Aşağıdaki gibi bir dersim var

//Assembly.dll
namespace TestAssembly{
    public class Main{

        public void Hello()
        { 
            var name = Console.ReadLine();
            Console.WriteLine("Hello() called");
            Console.WriteLine("Hello" + name + " at " + DateTime.Now);
        }

        public void Run(string parameters)
        { 
            Console.WriteLine("Run() called");
            Console.Write("You typed:"  + parameters);
        }

        public string TestNoParameters()
        {
            Console.WriteLine("TestNoParameters() called");
            return ("TestNoParameters() called");
        }

        public void Execute(object[] parameters)
        { 
            Console.WriteLine("Execute() called");
           Console.WriteLine("Number of parameters received: "  + parameters.Length);

           for(int i=0;i<parameters.Length;i++){
               Console.WriteLine(parameters[i]);
           }
        }

    }
}

Ardından, Parametrray öğesini çağırırken aşağıdaki gibi bir nesne dizisinin içine geçirmeniz gerekir. Aşağıdaki yöntem, çalışmanız gereken şeydir

private void ExecuteWithReflection(string methodName,object parameterObject = null)
{
    Assembly assembly = Assembly.LoadFile("Assembly.dll");
    Type typeInstance = assembly.GetType("TestAssembly.Main");

    if (typeInstance != null)
    {
        MethodInfo methodInfo = typeInstance.GetMethod(methodName);
        ParameterInfo[] parameterInfo = methodInfo.GetParameters();
        object classInstance = Activator.CreateInstance(typeInstance, null);

        if (parameterInfo.Length == 0)
        {
            // there is no parameter we can call with 'null'
            var result = methodInfo.Invoke(classInstance, null);
        }
        else
        {
            var result = methodInfo.Invoke(classInstance,new object[] { parameterObject } );
        }
    }
}

Bu yöntem, yöntemi çağırmayı kolaylaştırır, aşağıdaki gibi çağrılabilir

ExecuteWithReflection("Hello");
ExecuteWithReflection("Run","Vinod");
ExecuteWithReflection("TestNoParameters");
ExecuteWithReflection("Execute",new object[]{"Vinod","Srivastav"});

1

Yansıma yoluyla ağırlıklı ortalamayı çağırıyorum. Ve birden fazla parametre ile yöntem kullanmıştı.

Class cls = Class.forName(propFile.getProperty(formulaTyp));// reading class name from file

Object weightedobj = cls.newInstance(); // invoke empty constructor

Class<?>[] paramTypes = { String.class, BigDecimal[].class, BigDecimal[].class }; // 3 parameter having first is method name and other two are values and their weight
Method printDogMethod = weightedobj.getClass().getMethod("applyFormula", paramTypes); // created the object 
return BigDecimal.valueOf((Double) printDogMethod.invoke(weightedobj, formulaTyp, decimalnumber, weight)); calling the method

0
string result = this.GetType().GetMethod("Print").Invoke(this, new object[]{"firstParam", 157, "third_Parammmm" } );

harici .dll değilse (yerine this.GetType()kullanabilirsiniz typeof(YourClass)).

ps bu cevabı yayınlıyor çünkü birçok ziyaretçi bu cevap için buraya giriyor.

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.