The basic answer is that if you have a type Foo and your method takes parameter type Bar then Foo needs to either derive from Bar (possibly indirectly) or if Bar is an interface, it needs to implement Bar (again could be indirect).
If you were writing the code in C# you would get a compile time error if the argument isn't assignable to parameter type. For checks that you can do at runtime you can either cast, or use reflection:
using System;
using System.Diagnostics;
namespace ConsoleApplication3
{
interface Bar
{ }
class Foo
{ }
class Program
{
static void Main(string[] args)
{
Foo f = new Foo();
// this will throw InvalidCastException
try
{
Bar b = (Bar)f;
} catch(InvalidCastException) {}
// The assert will trigger because the types aren't assignment compatible
Type typeOfBar = typeof(Bar);
Type typeOfFoo = f.GetType();
Debug.Assert(typeOfBar.IsAssignableFrom(typeOfFoo));
// This is an alternative way of getting the type of Bar if you only know
// which method uses the parameter but not the type of the parameter
typeOfBar = typeof(Program).GetMethod("SomeMethod").GetParameters()[0].ParameterType;
Debug.Assert(typeOfBar.IsAssignableFrom(typeOfFoo));
}
public void SomeMethod(Bar b) { }
}
}
As for what metadata gets used, that gets a bit complex and probably is too low level for your purposes. However if you are particularly curious the CLI ECMA specification has these details.
HTH,
-Noah