매개 변수를 사용하여 리플렉션을 통해 메서드를 호출하려고하면 다음과 같은 결과가 나타납니다.
객체가 대상 유형과 일치하지 않습니다
매개 변수없이 메소드를 호출하면 정상적으로 작동합니다. 메소드를 호출하면 다음 코드를 기반으로 Test("TestNoParameters")
정상적으로 작동합니다. 그러나을 호출 Test("Run")
하면 예외가 발생합니다. 내 코드에 문제가 있습니까?
내 초기 목적은 예를 들어 객체 배열을 전달하는 public void Run(object[] options)
것이었지만 작동하지 않았으며 성공하지 않고 문자열과 같은 간단한 것을 시도했습니다.
// 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);
}
}
}
}
}
답변
null 매개 변수 배열을 사용한 호출과 마찬가지로 “methodInfo”를 “classInstance”로 변경하십시오.
result = methodInfo.Invoke(classInstance, parametersArray);
답변
당신은 바로 버그가 있습니다
result = methodInfo.Invoke(methodInfo, parametersArray);
그것은해야한다
result = methodInfo.Invoke(classInstance, parametersArray);
답변
근본적인 실수는 다음과 같습니다.
result = methodInfo.Invoke(methodInfo, parametersArray);
의 인스턴스에서 메소드를 호출하고 MethodInfo
있습니다. 호출하려는 객체 유형의 인스턴스를 전달해야합니다.
result = methodInfo.Invoke(classInstance, parametersArray);
답변
제공된 솔루션은 원격 어셈블리에서로드 된 유형의 인스턴스에는 작동하지 않습니다. 이를 위해 모든 상황에서 작동하는 솔루션이 있습니다. 여기에는 CreateInstance 호출을 통해 반환 된 유형의 명시 적 유형 다시 매핑이 포함됩니다.
이것이 원격 어셈블리에있는 classInstance를 만드는 방법입니다.
// sample of my CreateInstance call with an explicit assembly reference
object classInstance = Activator.CreateInstance(assemblyName, type.FullName);
그러나 위에 제공된 답변을 사용해도 여전히 같은 오류가 발생합니다. 방법은 다음과 같습니다.
// 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();
그런 다음 여기에 언급 된 다른 사용자와 같이하십시오.
답변
이렇게 짧게 사용하면 아무런 문제가 없습니다.
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);
}
답변
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);
}
}
}
}
답변
위의 모든 제안 된 답변으로 작업하려고했지만 아무것도 효과가없는 것 같습니다. 그래서 나는 여기서 나를 위해 일한 것을 설명하려고합니다.
나는 당신이 Main
당신의 질문에서와 같이 아래와 같은 메소드를 호출 하거나 단일 매개 변수로 호출한다면 , 매개 변수 유형을에서 string
로 변경하면 object
됩니다. 아래와 같은 수업이 있습니다
//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]);
}
}
}
}
그런 다음 호출하는 동안 아래와 같이 객체 배열 내부에 parameterArray를 전달해야합니다. 다음과 같은 방법으로 작업해야합니다
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 } );
}
}
}
이 메소드를 사용하면 메소드를 쉽게 호출 할 수 있으며 다음과 같이 호출 할 수 있습니다.
ExecuteWithReflection("Hello");
ExecuteWithReflection("Run","Vinod");
ExecuteWithReflection("TestNoParameters");
ExecuteWithReflection("Execute",new object[]{"Vinod","Srivastav"});
