私はパラメータを用いたリフレクションを介してメソッドを呼び出そうとしています、そして私は得ます:
オブジェクトがターゲットタイプと一致しません
私はパラメータなしでメソッドを呼び出すと、それはうまく機能します。私がメソッド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"});
リフレクションを通して加重平均を呼び出します。そして、複数のパラメータを持つメソッドを使用していました。
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