私は自分のC#プロジェクトの1つでリフレクションを使用しています。それはWindows8.1とWindowsPhone8.1を対象としたポータブルクラスライブラリです。
そのプロジェクトには、汎用パラメーターTGenericObjectを持つメソッドDoSomethingを持つIMyInterfaceという名前のインターフェイスがあります。MyClassという名前のクラスもあります。ある時点で、指定されたインターフェイスでメソッドDoSomethingをリフレクションによって検索する必要があります。そのため、実際のパラメーターの型(この例ではMyClass)を使用してTypeクラスのGetRuntimeMethodメソッドを使用しています。
ここで提供している例は、私が直面している問題を強調するためだけのものであることを忘れないでください。現実には、インターフェースIMyInterfaceとクラスMyClassは別のプロジェクトにあります。
これが取引です:GetRuntimeMethodがDoSomethingメソッドのMethodInfoを返すことを期待していましたが、そうではありませんでした:nullが返されます。
IMyInterfaceからDoSomethingメソッドを見つけるのに欠けている簡単なものはありますか、それとも手を汚す必要がありますか?
public interface IMyInterface
{
void DoSomething<TGenericObject>(TGenericObject myGenericObject);
}
public class MyClass
{ }
class Program
{
static void Main(string[] args)
{
MyClass myClassInst = new MyClass();
MethodInfo methodInfo = typeof (IMyInterface).GetRuntimeMethod("DoSomething", new [] { myClassInst.GetType() });
}
}
GetRuntimeMethodメソッドに期待したことを実際に実行する独自の拡張メソッドをコーディングすることができました。気になるのは、.NETが提供するGetRuntimeMethodメソッドがサンプルでnullを返す理由がまだわからないことです。
これが私の問題を一時的に修正する不完全なクラスです。これは非常に素朴なアプローチですが、出発点です。そのクラスには欠けているものがたくさんありますが、少なくとも、それは私が続けることを可能にする答えです。
public static class TypeExtensions
{
#region Public Methods
/// <summary>
/// Looks for the method in the type matching the name and arguments.
/// </summary>
/// <param name="type"></param>
/// <param name="methodName">
/// The name of the method to find.
/// </param>
/// <param name="args">
/// The types of the method's arguments to match.
/// </param>
/// <returns></returns>
/// <exception cref="ArgumentNullException">
/// Thrown if:
/// - The name of the method is not specified.
/// </exception>
public static MethodInfo GetRuntimeMethod(this Type type, string methodName, Type[] args)
{
if (ReferenceEquals(type, null))
throw new NullReferenceException("The type has not been specified.");
if (string.IsNullOrEmpty(methodName))
throw new ArgumentNullException("methodName", "The name of the method has not been specified.");
var methods = type.GetRuntimeMethods().Where(methodInfo => string.Equals(methodInfo.Name, methodName, StringComparison.OrdinalIgnoreCase)).ToList();
if (!methods.Any())
return null; // No methods have the specified name.
if (methods.Count == 1)
{
MethodInfo methodInfo = methods.Single();
return IsSignatureMatch(methodInfo, args) ? methodInfo : null;
}
// Oh noes, don't make me go there.
throw new NotImplementedException("Resolving overloaded methods is not implemented as of now.");
}
#endregion
#region Private Methods
/// <summary>
/// Finds out if the provided arguments matches the specified method's signature.
/// </summary>
/// <param name="methodInfo"></param>
/// <param name="args"></param>
/// <returns></returns>
private static bool IsSignatureMatch(MethodBase methodInfo, Type[] args)
{
Debug.Assert(!ReferenceEquals(methodInfo, null), "The methodInfo has not been specified.");
// Gets the parameters of the method to analyze.
ParameterInfo[] parameters = methodInfo.GetParameters();
int currentArgId = 0;
foreach (ParameterInfo parameterInfo in parameters)
{
if (!ReferenceEquals(args, null) && currentArgId < args.Length)
{
// Find out if the types matchs.
if (parameterInfo.ParameterType == args[currentArgId])
{
currentArgId++;
continue; // Yeah! Try the next one.
}
// Is this a generic parameter?
if (parameterInfo.ParameterType.IsGenericParameter)
{
// Gets the base type of the generic parameter.
Type baseType = parameterInfo.ParameterType.GetTypeInfo().BaseType;
// TODO: This is not good v and works with the most simple situation.
// Does the base type match?
if (args[currentArgId].GetTypeInfo().BaseType == baseType)
{
currentArgId++;
continue; // Yeah! Go on to the next parameter.
}
}
}
// Is this parameter optional or does it have a default value?
if (parameterInfo.IsOptional || parameterInfo.HasDefaultValue)
continue; // Uhum. So let's ignore this parameter for now.
// No need to go further. It does not match :(
return false;
}
// Ye!
return true;
}
#endregion
}
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加