C# Reflection: GetMethods(..) failing to retrieve anything - c#

I am currently trying to get a very specific set of methods but am failing to do so.
I need to get all methods that match a certain signature from all classes that implement a certain interface.
What I've got so far is:
IEnumerable<System.Type> classes = Assembly.GetAssembly(typeof(IActionMethod)).GetTypes().Where(x => x.GetInterface("IActionMethod") != null);
MethodInfo[] methods;
List<MethodInfo> relevant;
ParameterInfo[] parameters;
foreach(System.Type cls in classes)
{
methods = cls.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
relevant.Clear();
for(int i = 0; i < methods.Length; i++)
{
parameters = methods[i].GetParameters();
if(parameters.Length == 1 && parameters[0].GetType() == typeof(GameObject) && methods[i].ReturnType == typeof(void))
relevant.Add(methods[i]);
}
}
This code already fails at GetMethods(..)which is not returning any methods.
What I do not understand is, that I am able to receive all public methods of any of the relevant classes if they do not implement the interface.
The interface itself does not contain anything, I am only using it to "mark" the relevant classes, as I could not come up with any other solution to do so.
Can anyone tell me why the interface is rendering GetMethodsuseless or point me to the error in my code above?

I suspect this is the problem:
foreach(System.Type cls in classes)
{
methods = cls.GetType().GetMethods(...)
cls is already a Type, so calling GetType() on it will return System.Type (or a subclass). I suspect you just want:
foreach(System.Type cls in classes)
{
methods = cls.GetMethods(...)
It's also unclear why you're clearing the relevant list on each iteration. It means the only entries at the end will be the ones from the last class you look at - are you sure that's what you want?

As an aside, Microsoft recommends not using 'marker interfaces' and instead suggests using attributes. You can then use Memberinfo.IsDefined() instead of checking for the interface.

To find all classes that implements specific interface, you should use rather IsAssignableFrom because your code will omit classed that implement your interface indirectly:
Type interfaceType = typeof(IActionMethod);
Assembly assembly = Assembly.GetAssembly(interfaceType );
IEnumerable<System.Type> classes = assembly.GetTypes().Where(x => interfaceType.IsAssignableFrom(x));
Then, you probably want to call:
methods = cls.GetMethods(...)
because cls is your desired type, you are currently searching in its Type.

Related

Cast a less specified interface IInterface to a more specified IInterface<TKey,TValue>?

I have two interfaces
public interface ISerializableDictionary { ... }
public interface ISerializableDictionary<TKey,TValue>
: ISerializableDictionary { ... }
I need to cast from the former to the latter at run time using reflection.
It's clearly easy to interrogate the former with GetType().GetGenericArguments.
But how do I then do the cast? I have this code below but it is failing to compile, for the obvious reason that I am trying to use a variable as a type.
Type[] genericTypes = dictionary.GetType().GenericTypeArguments;
Type keyType = genericTypes[0];
Type valueType = genericTypes[1];
// this compiles but doesn't do the cast
Type dictType = typeof(SerializableDictionary<,>).MakeGenericType(keyType, valueType);
var createdDictionary = Activator.CreateInstance(dictType);
// this is the line that won't compile - 'dictionary' is a SerializableDictionary, and I want to access it through its typed generic interface
ISerializableDictionary<keyType,valueType> serializableDictionary = dictionary as ISerializableDictionary<keyType, valueType>;
The more specified interface has a method which I need to call. The less specified interface does not (and can't ever be, because the call needs a typed argument).
Is the solution something to do with dictionary.GetType().GetInterfaces()?
Any steer will be wildly appreciated. Programming solo at the moment so I don't have a team to call on, hence the query here.
UPDATE - in response to comments
The problem I am trying to solve is how to serialize members of an object where the members are themselves enumerable. I am trying to figure out how serialization libraries do it as a learning exercise and because I have a few ideas that I want to explore. Serialization & Reflection are not my main areas of programming so I am stumbling to learn them.
So I have (as reduced code):
public class ExperimentalSerializer<T>
{
public void Serialize(T objectToSerialize)
{
IEnumerable<object> collectionsToSerializeToCSV = objectToSerialize.GetEnumerableMembers();
foreach (object collectionToSerialize in collectionsToSerializeToCSV)
{
string csvString = "";
if (collectionToSerialize.IsDictionary())
{
// serialize dictionary here to csvString
// but cannot properly access contents through just IDictionary
// need IDictionary<TKey,TValue>
// ** ALSO SEE TEXT BELOW THIS CODE SNIPPET**
}
else if (collectionToSerialize.IsList())
{
// serialize list here to csvString
}
else if (collectionToSerialize.GetType().IsArray)
{
// serialize array here to csvString
}
// save csvString to somewhere useful here
}
}
}
And elsewhere I have an extension method:
public static IEnumerable<object> GetEnumerableMembers(this object objectToInterrogate)
{
Type objectType = objectToInterrogate.GetType();
// get the enumerable properties
PropertyInfo[] properties = objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
IEnumerable<PropertyInfo> enumerableProperties = properties.Where(propertInfo => propertInfo.PropertyType.GetInterfaces().Any(x => x == typeof(IEnumerable)));
IEnumerable<PropertyInfo> serializableProperties = enumerableProperties.Where(p => p.IsSerializable());
IEnumerable<object> enumerablePropertyValues = serializableProperties.Select(p => p.GetValue(objectToInterrogate, null));
// get the enumerable fields
FieldInfo[] fields = objectType.GetFields(BindingFlags.Instance | BindingFlags.Public);
IEnumerable<FieldInfo> enumerablefields = fields.Where(propertInfo => propertInfo.FieldType.GetInterfaces().Any(x => x == typeof(IEnumerable)));
IEnumerable<object> enumerablefieldValues = enumerablefields.Select(f => f.GetValue(objectToInterrogate));
// merge the two lists together
IEnumerable<object> enumerableMembers = enumerablePropertyValues.Union(enumerablefieldValues);
return enumerableMembers.ToList();
}
One specific challenge I am investigating is how to serialize an enumerable (Dictionary, List or array TValue[]) where TValue is itself a complex type (e.g. a class that can be serialized). This cannot be ascertained without knowing the type of TValue, but this cannot be retrieved from IDictionary or IList alone and these can only be enumerated with the type object.
This is the very specific point I am trying to investigate and potentially to control: how to determine TValue and then to work out if/how to serialize it in turn. My idea is to cast to more-specified generics with known type parameters but I get a bit lost at this point.
Hope this helps.
#SLaks points out in the comments:
Casting is inherently a compile-time operation. Casting to a type only known at runtime makes no sense. You can't call your method if its types are not known at compile-time.
That's absolutely right. You can, of course, still call the intended method at runtime, but you'll need to use (more) reflection to do it, since you have no way to get the compiler to generate a statically-typed call.
To do this, take the Type object you already constructed using MakeGenericType(), and call GetMethod() on it to get the Type.MethodInfo object corresponding to the method to call. Then, call MethodInfo.Invoke().
Type dictType = typeof(SerializableDictionary<,>).MakeGenericType(keyType, valueType);
MethodInfo method = dictType.GetMethod("MyMethod");
object returnValue = method.Invoke(dictionary, new object[] { /* arguments */ });
TMI...
When you write dictionary.MyMethod(), the C# compiler generates a Callvirt IL (byte code) instruction. The object to call the method on (and the arguments to the method) are pushed onto the stack, and the argument to Callvirt is the metadata token corresponding to the type-qualified ISerializableDictionary<TKey,TValue>.MyMethod method. This is the normal calling mechanism in .NET. When you (and the compiler) don't know what TKey and TValue are at compile time, there's no way to get the right metadata token for the method, and no way to generate the Callvirt. That's why you have to use the reflection API.
You can, however, use something like DynamicMethod to generate your own IL and JIT it at runtime. Once JITted, the call is just as fast as one statically generated by the compiler. There is of course significant overhead to generating a dynamic method, but it's a one-time overhead.
Of course, #DavidL points out:
The approach here seems wildly off-course. Instead of asking for a specific solution, can you please describe the specific concrete problem that you are trying to solve?
That, too, is absolutely right. So don't do what I just suggested unless you really, really know what you're doing and have a really, really good reason. (Hint: You don't.) But I thought this information might give you a better overall picture of why you can't do what you expected to do.

How do I determine if a property is a user-defined type in C#?

How do I determine if a property is a user-defined type? I tried to use IsClass as shown below but its value was true for String properties (and who knows what else).
foreach (var property in type.GetProperties()) {
if (property.PropertyType.IsClass) {
// do something with property
}
}
* Updated for more clarity *
I am trying to traverse a given type's definition and if the given type or any of its public properties are defined within the assembly, I am searching for an embedded JavaScript document. I just don't want to waste processing resources and time on native .NET types.
#Bobson made a really good point:
"...Unlike some other languages, C# does not make any actual
distinction between "user-defined" and "standard" types."
Technically, #Bobson gave the answer; there is no distinguishing difference between a user-defined type and one defined in the .NET Framework or any other assembly for that matter.
However, I found a couple useful ways to determine if a type is user-defined.
To search for all types defined within the given type's assembly, this works great:
foreach (var property in type.GetProperties()) {
if (property.PropertyType.IsClass
&& property.PropertyType.Assembly.FullName == type.Assembly.FullName) {
// do something with property
}
}
If the types can be defined in various assemblies, excluding the System namespace works in most cases:
foreach (var property in type.GetProperties()) {
if (property.PropertyType.IsClass
&& !property.PropertyType.FullName.StartsWith("System.")) {
// do something with property
}
}
If by "user-defined" you mean that it is not part of the standard assembly (mscorlib) then you can do something along the lines of this:
if(typeof(SomeType).Assembly.GetName().Name != "mscorlib") {
// user-defined!
}
However this will also consider types from external assemblies (aka: libraries) to be considered "user-defined". If you only want those in your current assembly then you can use
typeof(SomeType).Assembly == Assembly.GetExecutingAssembly()
I wrote a generic populator for unit testing that assigns predictable values to my objects and came across this kind of problem. In my case I wanted to know which of my properties were objects so that I could recursively populate those object properties, again with predictable values.
It seemed to me that introducing an interface implemented only by the classes that I was interested in traversing was the best way to do this. You can then test to see if your property is an object of interest:
public static bool IsMyInterface(this Type propertyType)
{
return propertyType.GetInterface("MyInterfaceName") != null;
}
Say your project is named "Foobar" and everything you make is under that namespace. You can test to see if you've written it by the following method:
typeof(SomeType).Namespace.Contains("Foobar");
I struggled with this as well when creating a log when updating the database. I did not want the classes to be shown in the log as they never == between data and dto.
foreach (PropertyType item in properties)
{
if((item.PropertyType.IsClass && item.PropertyType.FullName.StartsWith("System.")) || !item.PropertyType.IsClass)
{
//...do stuff
}
}
This allowed me to deal with strings and the likes which are flagged as classes.
If by "user-defined" type you mean type that was declared in your executing assembly then you can obtain list of that types like in this sample c# console application:
class Program
{
static void Main( string[] args )
{
var currentAssembly = Assembly.GetExecutingAssembly();
var localTypes = currentAssembly.GetTypes();
}
}
UPDATE:
If you want to obtain list of types from all referenced assemblies:
class Program
{
static void Main( string[] args )
{
var currentAssembly = Assembly.GetExecutingAssembly();
var referencedAssemblies = currentAssembly.GetReferencedAssemblies();
var typesFromReferencedAssemblies = referencedAssemblies.Select( assemblyName => Assembly.ReflectionOnlyLoad( assemblyName.FullName ) ).SelectMany( assembly => assembly.GetTypes() );
}
}
Just be aware that Program type will also be in that list. Is this sufficient answer to your problem?

a generic extension method for classes with common methods but no inheritance

I'm working with a COM library in my .Net 3.5 project that has a bunch (about 20-30) of collection type interfaces. Each of these classes exposes things a property called Count and methods called ItemByIndex(int) and GetEnumerator() (which is of type System.Collections.IEnumerator).
However, each of these interfaces is implemented them on their own and not in a common parent class.
Is there a way to write a generic extension method that converts the collection object to a List<>? This is what I'm currently doing, but I have 20 or so of these methods copied and pasted.
public static List<iml.IManDocument> ToList(this iml.IManDocuments source)
{
List<iManDocument> results = new List<iManDocument>(source.Count);
for (int i = 1; i <= source.Count; i++)
{
results.Add((iml.IManDocument)source.ItemByIndex(i));
}
return results;
}
Unfortunately you can not add extension methods based on existing methods, and neither you can add interfaces dynamically to types that fit those interface (both would be great and useful things).
One option would be to add the extension method for object and use reflection to figure out whether the required methods and properties exists.
public static List<iml.IManDocument> ToListByReflection(this object source)
{
var type = source.GetType();
var countProperty = type.GetProperty("Count");
var itemByIndexMethod = type.GetMethod("ItemByIndex", new[] { typeof(int) });
if (countProperty == null || itemByIndexMethod == null)
{
throw new Exception("Type does not offer required methods.");
}
var count = countProperty.GetValue(source);
var results = new List<iManDocument>(count);
for (int i = 1; i <= count; i++)
{
results.Add((iml.IManDocument)itemByIndexMethod.Invoke(source, new object[] { i });
}
return results;
}
For better performance you could even cache the property and method infos for each different type.
But just writing a method like you did is in my opinion really the better option. It's clearer what it does, it's type-safe at compilation time (worth a lot!) and faster than reflection. It's just one time writing per type, and mostly it's copy-paste anyway.
Ideally, you should make your types implement IList<T> or IReadOnlyList<T>. However, I'm guessing you can't do that...
You can do this with builtin methods (making use of the fact that they are IEnumerable):
var list = myIManDocuments.Cast<IManDocument>().ToList();
You could do it with dynamic, but this has downsides, the biggest one being that you don't get any compile-time checking that you're doing this with compatible types.
public static List<T> ToList<T>(dynamic source)
{
List<T> results = new List<T>(source.Count);
for (int i = 1; i <= source.Count; i++)
{
results.Add(source.ItemByIndex(i));
}
return results;
}
Use like:
var list = MyUtil.ToList<IManDocument>(myIManDocuments);
List has a constructor which accepts an IEnumerable as argument. Since IEnumerable has only (the generic) GetEnumerator you could easily make your interfaces derive from IEnumerable (the generic one) and use the List constructor.
You can wrap the library classes (using the http://en.wikipedia.org/wiki/Adapter_pattern ), and make them implement the IList interface.

Collection of Generic Lists

I have a function which needs to go through a class' types and identify a specific type. If I find that type, I want to cast it to the type that I know it is. But in the code below, the following case is failing:
BaseTableObjectList<BaseTableObject> obj = pi.GetValue(item, null) as BaseTableObjectList<BaseTableObject>;
Here is the code. Basically, I am making an iterator which returns certain properties. Why can't I cast?
foreach (PropertyInfo pi in item.GetType().GetProperties())
{
if (pi.PropertyType.BaseType == null) continue; // skip interfaces
if (!pi.PropertyType.BaseType.IsGenericType) continue; // only interested in childlists
Type[] types = pi.PropertyType.BaseType.GetGenericArguments();
// is my generic argument derived from baseObject?
if (typeof(BaseTableObject).IsAssignableFrom(types[0]))
{
// this is a child we want
log.Info(types[0].Name);
BaseTableObjectList<BaseTableObject> obj = pi.GetValue(item, null) as BaseTableObjectList<BaseTableObject>;
yield return obj;
}
}
Make sure that pi.GetValue(item, null).GetType() is actually the type you want to cast to. It seems like it returns BaseTableObject instead BaseTableObjectList<BaseTableObject>
If your class Company : BaseTableObject and your CompanyList : BaseTableObjectList<Company> then your result can be cast to BaseTableObjectList<BaseTableObject> by using CompanyList.Cast<BaseTableObject>()
Edit2: From your comments, I think the following code will do the work.
BaseTableObjectList<BaseTableObject> obj = new BaseTableObjectList<BaseTableObject>((pi.GetValue(item, null) as System.Collections.IEnumerable).Cast<BaseTableObject>());
The problem you have I think is one of covariance, which only applies to interfaces. If you had a IBaseTableObjectList<out T> where T : BaseTableObject the cast wouldn't fail. Covariance for generics is only supported on delegates and interfaces not on base classes:
http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
In C#, variance is supported in the following scenarios:
Covariance in arrays (since C# 1.0)
Covariance and contravariance in delegates, also known as “method group variance” (since C# 2.0)
Variance for generic type parameters in interfaces and delegates (since C# 4.0)
This is essentially the same problem is assigning a List<string> to an IEnumerable<object> which is one of the examples in the linked article.

Finding all classes containing a method in C#

I want to search through all classes in a namespace for those containing a certain method. If a class contains a method then I want to create an instance of the class and run the method.
Obviously I have to start with reflection but I'm stuck on where to go.
Edit:
Interfaces are not the way I want to do this.
What I'm looking for is embedding testing functions into the code but a single calling interface. If there's a self-test function, call it. If there isn't, ignore it.
Create an interface that declares the method and then have various classes implement that interface.
You can then use reflection to find all types within an assembly that implement that interface.
From there you'll need to create an instance of each type and then call the method. The implementation details will vary depending on what you are trying to do.
Update based on comments:
I still think an interface (or attribute) is the way to go. This is how it would work with an interface.
interface ISelfTester
{
void SelfTest();
}
class SomeClass : ISelfTester
{
/* ... */
public void SelfTest()
{
// test code
}
/* ... */
}
You could then invoke each type's SelfTest method like so (borrowing from Dathan and Darren Kopp):
var type = typeof(ISelfTester);
var types = AppDomain.CurrentDomain.GetAssemblies()
.Select(x => x.GetTypes())
.SelectMany(x => x)
.Where(x => x.Namespace == "My.Name.Space" && type.IsAssignableFrom(x));
foreach (Type t in types)
{
ISelfTester obj = Activator.CreateInstance(t) as ISelfTester;
obj.SelfTest();
}
Without more information about what distinguishes the method, I'm just going to assume it's distinguished by name, and it's public. The name assumption is dangerous, so I wouldn't recommend doing this, but the following should do what you want (assuming Activator is able to create an instance).
EDIT: Added Where(x => x.Namespace == "My.Name.Space") to limit the results to a single target namespace.
EDIT: Added if ... else to handle the case of static methods.
var methods = AppDomain.CurrentDomain.GetAssemblies()
.Select(x => x.GetTypes())
.SelectMany(x => x)
.Where(x => x.Namespace == "My.Name.Space")
.Where(c => c.GetMethod("MethodName") != null)
.Select(c => c.GetMethod("MethodName"));
foreach (MethodInfo mi in methods)
{
if (mi.IsStatic)
{
mi.Invoke(null, null); // replace null with the appropriate arguments
}
else if (!mi.DeclaringType.IsAbstract)
{
var obj = Activator.CreateInstance(mi.DeclaringType);
mi.Invoke(obj, null); // replace null with the appropriate arguments
}
}
If you have control over the types, though, jrummel's suggestion about interfaces is a much safer way to do this.
One option would be to use Reflection, as described above, but rather than finding the method by name, look for a method tagged with an appropriate custom attribute. This is similar to what the MS DataContractSerializer does with attributes like [OnDeserializing]. This way the class implementer is specifically spelling out their intent for the method, rather than having it suddenly do something unexpected as a result of it having a particular name.
On a side note, since what you're after is a test method, you might check out something like NUnit. There are several excellent free unit testing frameworks out there. They also provide additional features that can help with your testing, as they provide the scaffolding for the different types of test assertions you might want to make.

Categories

Resources