How to create and iterate over a method group list - c#

I have a series of generic methods that accept a type to run. For instance:
db.CreateTable<MyClassName>();
I want to be able to create a list of classes and then iterate over the list like:
foreach(var class in classList)
{
db.CreateTable<class>();
db.CheckStatus<class>();
// ... etc
}
VS says the parameter is a method group. I googled this and docs say this is a delegate. How do i create a list of delegates pointing to my classes that I can then iterate over and use as reference in call to generic method?

My answer makes an assumption I just realized might not be valid: I am assuming that classList is a IEnumerable<Type>. If that is incorrect, my answer will need to be revised.
It needs to be something like this.
var fn = db.GetType().GetMethod("CheckStatus");
foreach (var cls in classList)
{
var fn2 = fn.MakeGenericMethod(cls);
fn2.Invoke(db, null);
}
Okay, what's going on here. We get a reference to the method on the db object called "CheckStatus". If there are overloads of that method, you'll need to use one of the overloads of GetMethod to get it.
Then, we make it a closed generic method. So in the first part, we get a method CheckStatus<T>, where T is not specified. This is an open generic. You need to fill in the generic with your type information. That is what MakeGenericMethod does. In effect, it gives you CheckStatus<cls>. You can then invoke this method on db.
For more information on open/closed generics, see: What exactly is an “open generic type” in .NET?

Related

C#: Pass reflection type into class constructor

I've got a generic method that takes an arbitrary JObject (from JSON.net) and converts it into the generically typed object.
So, let's simplify my conversion method to look like the following:
private async Task<T> ConvertToObject(JObject obj) {
//Lots of other stuff yielding in the creation of newObj
var result = newObj.ToObject<T>();
return result;
}
Now this method works fine as-is, but I want to modify the method so I can properly do the same for complex properties within the generic object that aren't available in my JObject (e.g. I have to look them up separately, do this same conversion and apply to this object result).
My approach so far is to loop through all the properties, identify the complex types, perform the lookup to retrieve their values from my data store, then execute the above against them (potentially recursively if they too have any complex objects), then write that value back out to this complex property, repeat for any others and then as before, return that result.
I'm retrieving the properties via Reflection:
var properties = result.GetType().GetProperties();
foreach (var property in properties) {
if (IsSimple(property.PropertyType)
continue;
//Do external lookup
var convertedValue = new ConversionTool<>().Lookup(query);
}
Now, that last line is where I'm having my problem. I'm expected to pass a class name into this, not just a type, but I only know the type at runtime per the reflection methods above. I found a post at http://www.paulbatum.com/2008/08/less-fragile-way-to-invoke-generic.html detailing how to make this work if I were simply passing the generic type into a method and he explains the issue with using Activator.CreateInstance in the comments, but it seems like I know the type I'd want to put there - I just don't know it until it runs (and I retrieve it via reflection).
This seems like an issue that ORMs would run into when it comes to populating complex properties of their entities, but I'm having a difficult time finding how they're doing this.
Given that the caller of this method is aware at runtime what the intended type is, how might I go about passing that type into the generic class constructor so I might call it recursively for each complex member of a given type?

C# Reflection with generics

I have been searching for this for some time but not gotten anywhere. I want to do the following:
Given a type say Dictionary<string,MyClass> and say its method ContainsKey(string) - at run time
I want to be able to extract out the 'Generic signature' of this method. That is I want to get
Boolean Dictionary<TKey,TValue>.ContainsKey(TKey) ( and not Boolean ContainsKey(string) )
I know that this is possible by doing the following
var untyped_methods = typeof(DictObject).GetGenericTypeDefition().GetMethods();
// and extract the method info corresponding to ContainsKey
However is is possible to get this information directly from the methods reflected from the
actual type and not from the Generic types ? Meaning Can I get the generic definition
from methods that have been obtained as follows :
var actual_typed_methods = typeof(DictObject).GetMethods()
In essence is it possible to get the "un-typed" method signatures from MethodInfo objects returned in the second snippet above directly (not via comparing the lists and figuring out)
Thanks
EDIT: Maybe this did what you wanted. Not sure if you were actually looking to Invoke or not.
If Invoking, then no (see below). If you just want the definition, then you can use typeof(Dictionary<,>) to get the raw generic definitions.
Unfortunately, no if you are wanting to Invoke.
Demonstration of why:
void Main()
{
var genericDictionaryType = typeof(Dictionary<,>);
var method = genericDictionaryType.GetMethod("ContainsKey");
var dict = new Dictionary<string, string>();
dict.Add("foo", "bar");
Console.WriteLine("{0}", method.Invoke(dict, new[] { "foo" }));
}
Yields the following error:
Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.
Sounds simple enough to fix. Just call method.MakeGenericMethod(typeof(string)); to get the actual typed MethodInfo object.
Unfortunately again, you cannot.
Boolean ContainsKey(TKey) is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.
Reason for this is because the method defined as bool ContainsKey(TKey) instead of bool ContainsKey<TKey>(TKey).
You will need to get the ContainsKey method from the correct Dictionary<TK,TV> signature in order to use it.

C# Enum.GetValues() - using non-boxed object

I'm trying to write a generic method that will return specific markup when passed an enum. Below is the method which has been reduced to the minimum required code for this question.
public static string GetMarkup(Type enumType)
{
StringBuilder builder = new StringBuilder();
foreach (var val in Enum.GetValues(enumType))
{
builder.Append(val.ToString());
}
return builder.ToString();
}
The method is called like this where CopyType is an enum:
GetDropDownListHtml(typeof(CopyType))
The goal is to be able to call ToString() extension methods I've written for the enums I'll pass into this method. The problem is that to make the method generic, I need to use var to declare my variable in the foreach declaration, but that boxes it. Instead of an enum of CopyType, I have an object that is the boxed CopyType.
In response, I've tried many thinks like this, but to no avail:
((typeof(enumType))val.ToString()
Any ideas?
There's no way to use extension methods to do this to a specific enum. You either need to extend your extension method to support all Enum types, add an is statement in there which you can use to only cast it when necessary, or write a special overload to this function which you call just for this type of enum. This has to do with how extension methods are actually implemented.
The compiler turns an extension method into its static form: myCopyType.ToString() becomes CopyType.ToString(myCopyType) when compiled. But with your scenario (or even with generics) the compiler can't tell what type to use, because the type isn't determined until runtime.
This leaves the three choices above.
In my own code, I went with the first option, based on the code here. You'll be able to call .GetLabel() on any Enum type, and you can put your special labels on this one specifically.
Additionally, you'll need to use foreach (Enum val in ... instead, so as to make sure the compiler knows it's an Enum.

Reasons to specify generic types in LINQ extension methods

Just out of curiosity:
Many LINQ extension methods exist as both generic and non-generic variants, for example Any and Any<>, Where and Where<> etc. Writing my queries I usually use the non-generic variants and it works fine.
What would be the cases when one has to use generic methods?
--- edit ---
P.S.: I am aware of the fact that internally only generic methods are called and the compiler tries to resolve the content of the generic brackets <> during compilation.
My question is rather what are the cases then one has to provide the type explicitly and not to rely on the compiler's intuition?
Always. The C# compiler is smart enough to infer what the type of the method is based on the parameters. This is important when the type is anonymous, and thus has no name.
obj.SomeMethod(123); //these calls are the same
obj.SomeMethod<int>(123);
obj.SomeMethod(new { foo = 123 }); //what type would I write here?!
Edit: To be clear, you are always calling the generic method. It just looks like a non-generic method, since the compiler and Intellisense are smart.
Edit: To your updated question, you would want to be specific if you want to use a type that is not the type of the object you are passing. There are two such cases:
If the parameter implements an interface, and you want to operate on that interface, not the concrete type, then you should specify the interface:
obj.DoSomething<IEnumerable<Foo>>( new List<Foo>() );
If the parameter is implicitly convertible to another type, and you want to use the second type, then you should specify it:
obj.DoSomethingElse<long> ( 123 ); //123 is actually an int, but convertible to long
On the other hand, if you need a cast to do the conversion (or you insert one anyway), then you don't need to specify:
obj.DoYetAnotherThing( (Transformed)new MyThing() ); // calls DoYetAnotherThing<Transformed>
One example I ran into today:
ObjectSet<User> users = context.Users;
var usersThatMatch = criteria.Aggregate(users, (u, c) => u.Where(c));
The above code won't work because the .Where method doesn't return an ObjectSet<User>. You could get around this one of two ways. I could call .AsQueryable() on users, to make sure it's strongly typed as an IQueryable, or I could pass specific type arguments into the Aggregate method:
criteria.Aggregate<Func<User, bool>, IEnumerable<User>>(
PersonSet, (u, c) => u.Where(c));
Another couple of more common examples are the Cast and OfType methods, which have no way to infer what type you want, and in many cases are being called on a non-generic collection in the first place.
In general, the folks that designed the LINQ methods went out of their way to avoid the need to use explicit types in these generic methods, and for the most part you don't need to. I'd say it's best to know it's an option, but avoid doing it unless you find it necessary.

How do you call a method by its "name"?

What would be the way to call some method by name, like "Method1", if I've got an Object and it's Type?
I want to do something like this:
Object o;
Type t;
// At this point I know, that 'o' actually has
// 't' as it's type.
// And I know that 't' definitely has a public method 'Method1'.
// So, I want to do something like:
Reflection.CallMethodByName(o, "Method1");
Is this somehow possible? I do realize that this would be slow, it's inconvenient, but unfortunately I've got no other ways to implement this in my case.
If the concrete method name is only known at runtime, you can't use dynamic and need to use something like this:
t.GetMethod("Method1").Invoke(o, null);
This assumes, that Method1 has no parameters. If it does, you need to use one of the overloads of GetMethod and pass the parameters as the second parameter to Invoke.
You would use:
// Use BindingFlags for non-public methods etc
MethodInfo method = t.GetMethod("Method1");
// null means "no arguments". You can pass an object[] with arguments.
method.Invoke(o, null);
See MethodBase.Invoke docs for more information - e.g. passing arguments.
Stephen's approach using dynamic will probably be faster (and definitely easier to read) if you're using C# 4 and you know the method name at compile time.
(If at all possible, it would be nicer to make the type involved implement a well-known interface instead, of course.)
The easiest way:
dynamic myObject = o;
myObject.Method1();

Categories

Resources