私はCecilを使用して、コンベンションテスト用のインターフェイスを使用して汎用メソッドへの呼び出しのインスタンスを見つけようとしています。 MethodReference
からジェネリックタイプを特定できません。農場まで、ジェネリックメソッドに渡される型を見つけるためにCecilを使うにはどうすればいいですか?
private interface IAnimal
{
}
private class Duck : IAnimal
{
}
private class Farm
{
private readonly ICollection<string> _animals = new List<string>();
public void Add<T>()
{
_animals.Add(typeof(T).Name);
}
public override string ToString()
{
return string.Join(", ", _animals);
}
}
static Farm FarmFactory()
{
var farm = new Farm();
farm.Add<Duck>();
farm.Add<Duck>();
farm.Add<IAnimal>(); // whoops
farm.Add<Duck>();
return farm;
}
private static void Main(string[] args)
{
var farm = FarmFactory();
Console.WriteLine("Farm:");
Console.WriteLine(farm);
// Use Cecil to find the call to farm.Add<IAnimal>():
Console.WriteLine("Errors:");
FindErrors();
Console.Read();
}
は、だから私はコンパイル時のエラー、あるいは実行時エラーを与えることはありませんfarm.Add<IAnimal>()
への呼び出しを、見つけたい:
私は基本的なテストを設定していますリフレクションによって型のインスタンスを作成しようとしました。私の実際のユースケースは、DIコンテナのコンベンションテストです。
セシルはFindErrors()
方法でそれに入って来:私はFarm::Add
を呼び出すときに使用される一般的なタイプを識別するために失敗していますどこ
private static void FindErrors()
{
var methods = AssemblyDefinition.ReadAssembly(typeof (Farm).Assembly.Location)
.Modules
.SelectMany(module => module.Types)
.SelectMany(type => type.Methods)
.Where(method => method.HasBody)
.ToArray()
;
var callsToFarmDotAdd = methods
.Select(method => new
{
Name = method.Name,
MethodReferences = GetCallsToFarmDotAdd(method)
})
.Where(x => x.MethodReferences.Any())
.ToArray()
;
var testCases = callsToFarmDotAdd
.SelectMany(x => x.MethodReferences)
;
var callsInError = testCases
.Where(test => !test.GenericParameters[0].Resolve().IsClass)
;
foreach (var error in callsInError)
{
Console.WriteLine(error.FullName);
}
}
private static IEnumerable<MethodReference> GetCallsToFarmDotAdd(MethodDefinition method)
{
return method.Body.Instructions
.Where(instruction => instruction.OpCode == OpCodes.Callvirt)
.Select(instruction => (MethodReference) instruction.Operand)
.Where(methodReference => methodReference.FullName.Contains("Farm::Add"))
;
}
callsInError
一部です。具体的には、MethodReference
のGenericParameters
プロパティは空です。したがって、GenericParameters[0]
はArgumentOutOfRangeException
となります。私はMethodReference
を調べましたが、私は確かにFarm::Add
への呼び出しを受けていますが、便利ではないFullName
プロパティを除き、使用されているジェネリックタイプに関連するものはどこにもありません。
コールで使用されるジェネリックタイプを識別するためにCecilを取得するにはどうすればよいですか?