1

I have a method where the type of an object is known ahead of time and that object (along with its type) needs to be passed into a method, for instance:

public void foo()
{
  string type_of_object = "person";
  person p = new person();

  // insert code here
}

public T method<T>(object obj)
{
  // some functions go here
  return (T)...
}

Given that there could be hundreds of types that I have to deal with, I don't want to do a switch statement over each type. I can't seem to figure out how to do something along these lines:

var foo = method<person.GetType()>(p);

Any takers?

joelc
  • 2,687
  • 5
  • 40
  • 60
  • 1
    I realize sometimes things can be out of your control, but how come this is necessary in the first place? – Ocelot20 Jul 09 '13 at 21:15
  • A generic parameter must be a compile-time constant, whether inferred or explicit. You cannot provide a Type value, you must actually provide a Type name. Basically, you can't do what you're asking. – Curtis Rutland Jul 09 '13 at 21:17
  • The back half of this particular application is generic. We're trying to increase the amount of the code that is generic. There is a switch statement with each type listed and the exact same code block under each case (with types changed of course) but the problem is that the number of types is about to grow to be very, very large. Cheers – joelc Jul 09 '13 at 21:17
  • There's not a nice way.. type parameters are evaluated at compile-time. – Blorgbeard Jul 09 '13 at 21:17
  • Not even if you use Reflection? – joelc Jul 09 '13 at 21:17
  • 1
    I don't count that as "nice" :P – Blorgbeard Jul 09 '13 at 21:18
  • If you know a solution using Reflection, I'd love to hear it. I can't seem to find anything that gives a clear indication of how to do it. Thanks! – joelc Jul 09 '13 at 21:18
  • 2
    If the parameter is the same type as the return type, you can just declare your method as `public T method(T obj)` and call it simply like `var foo = method(p);`. – Styxxy Jul 09 '13 at 21:19
  • If you have `person p = new person()` we know the runtime type of `p` already, it's `person`. Then just write `method`. Maybe I don't understand the problem? – Jeppe Stig Nielsen Jul 09 '13 at 21:22
  • I'd like to do that @Styxxy, but there are a couple of different methods that would need to be called in succession that need to be aware of the type. – joelc Jul 09 '13 at 21:22
  • Does the caller _know_ that `T` is compatible (perhaps as a base class or interface) with the type denoted in `type_of_object`? Like how do you intend to _use_ the result of `method(p)`? Will it return an `object` type, or might you call `BaseType foo = method(p)` where `p` has information for an instance of `BaseType` or a compatible subclass/interface of `BaseType`? – Chris Sinclair Jul 09 '13 at 21:22
  • @Chris these methods would return an object. – joelc Jul 09 '13 at 21:24
  • @haxor You mean it's okay if the method signature is `public object method(object)`? EDIT: or rather `public object method(string myTypeName)`? – Chris Sinclair Jul 09 '13 at 21:25
  • @Chris I cannot pass in the string containing the object type into the method :-/ The method has a signature like `T method(object obj)` – joelc Jul 09 '13 at 21:28
  • @haxor If you are planning on doing some more things, try including a little bit more code (but not too much) of what your intends are. Maybe we can suggest a better way of solving your problem (maybe different than your approach). – Styxxy Jul 09 '13 at 21:28
  • @Styxxy where I have one call to `T method(object obj)` in `foo()` there may be multiple calls to multiple separate methods. – joelc Jul 09 '13 at 21:30
  • possible duplicate of [How to use reflection to call generic Method?](http://stackoverflow.com/questions/232535/how-to-use-reflection-to-call-generic-method) – nawfal Jan 17 '14 at 16:42

2 Answers2

3

You can use reflection. In your case would be something like:

MethodInfo method = this.GetType().GetMethod("method");
MethodInfo generic = method.MakeGenericMethod(p.GetType());
generic.Invoke(this, p);

Check this response:How do I use reflection to call a generic method?

Community
  • 1
  • 1
fcuesta
  • 4,429
  • 1
  • 18
  • 13
  • 2
    I think your `person` should be either `p.GetType()` or `typeof(person)` - trying to use the names from the question. – Jeppe Stig Nielsen Jul 09 '13 at 21:26
  • I think this has the same issue. The "person" component is stored in a string. I believe that I would need to somehow pass in a string as a parameter to the second line in your solution. – joelc Jul 09 '13 at 21:27
  • If the person is stored in a string, how do you create a new person object? – fcuesta Jul 09 '13 at 21:28
  • It was created ahead of time. My code above showing where the object was created was only for context. – joelc Jul 09 '13 at 21:28
  • 1
    well, then p.GetType() will return the proper type! – fcuesta Jul 09 '13 at 21:29
  • Sorry, let me edit my question above. The person is stored in an object, not in a person. – joelc Jul 09 '13 at 21:31
  • Maybe what the asker wants is `.MakeGenericMethod(Type.GetType(type_of_object))`. It's not very clear. – Jeppe Stig Nielsen Jul 09 '13 at 21:31
  • 1
    @haxor GetType will get the type of the object, not the variable. It doesn't matter whether it's pointed to by an `object` variable if it's still a `person` underneath. – Blorgbeard Jul 09 '13 at 21:33
  • 1
    GetType() returns the run-time class of the object, so even if person is stored in an object variable you will get the correct type. – fcuesta Jul 09 '13 at 21:33
  • Can you explain how to make this fit into the code example above? – joelc Jul 09 '13 at 21:35
  • Can you show an example of the switch statement you want to avoid? That will probably clarify how you pretend to use this code. – fcuesta Jul 09 '13 at 21:38
  • Sure thing `switch (type_of_object) { case "person": break; case "dog": break; case "cat": break; }` - this comment editor isn't allowing line breaks, so imagine if each case statement had a call to a method that requires like `case "person": some_obj = method(p)` – joelc Jul 09 '13 at 21:40
  • 2
    Then you can use Type.GetType("yournamespace.person") to get the proper type. Use it in method.MakeGenericMethod(Type.GetType("yournamespace.person")); – fcuesta Jul 09 '13 at 21:44
  • Thanks @fcuesta, pardon me if I'm not completely understanding your answer. How would I get a return object out of `generic.Invoke(this, p);`, would it be `object obj = generic.Invoke(this, p);`? – joelc Jul 09 '13 at 22:07
  • Yes, you can do that. If you want a specific class you can: person obj = generic.Invoke(this, p) as person; – fcuesta Jul 09 '13 at 23:16
0

I think the reflection libraries should help with this. Reflection can be slow, but this could be sped up if, at the beginning of the program, you make a dictionary of strings to types.

var dict = Assembly.GetExecutingAssembly().GetTypes().ToDictionary(t => t.Name, t => t);

Then, in your own code:

Type targetType;
if (!dict.TryGet(type_of_object, out targetType)) {
  // log error with unknown type
}

I wrote that in the answer-box, not an editor, so apologies if I missed something simple. I'm also not entirely sure I have an idea of what your "some functions" would be. Also, my code does nothing to account for multiple types, in seperate namespaces, with the same name. You may want to consider that if you're doing more than "String, Int32..."

Katana314
  • 8,429
  • 2
  • 28
  • 36