Helper method for calling generic methods with reflection

Does anyone have a better way to do the following:

typeof(Service).GetMethod("UpdateData")
    .MakeGenericMethod(dataType)
    .Invoke(_myService, new object[]{ editData, metaData });

I'd love to do something like:

_myService.UpdateData<dataType>(editData, metaData);

But the <> accessor for generics will not take Type objects. I'm looking for a helper, utility, accessor, or something to make those generic method calls with reflection less cumbersome or at least centralized.

More Specific Example

public class UserService : IUserService
{
  async Task<User> UpdateUser<T>(User user, JsonPatchDocument<T> patch){ //do code }
}

Type dtoType = MagicService.getDynamicDtoType();
Type patchType = typeof(JsonPatchDocument<>).MakeGenericType(dtoType);
dynamic patchDoc = _mapper.Map(patch, typeof(JsonPatchDocument<User>), patchType);
User updateUser = await (Task<User>)typeof(UserService).GetMethod("UpdateUser").MakeGenericMethod(dtoType).Invoke(_userService, new object[]{user, patchDoc})

This actually ends up with two issues. One, the dynamic patchDoc isn't the right type to be used in UpdateUser, which I have a separate question in Stackoverflow about (but you can use duck typing here), and the messy calling of that generic method call with reflection. I'm trying to solve both, but for this question I want to clean up the call. If you have ideas on the other piece, which is really a separate issue: Declaring a type in C# with a Type instance

1 answer

  • answered 2019-07-10 23:20 Scott Hannen

    This answer does not use reflection, but may make your code easier to work with in some circumstances.

    We could have a class like this:

    public class MyService
    {
        public void UpdateData<T>(Something data, Something otherData)
        {
            // do stuff
        }
    }
    

    Later we find that we have to call it using a Type variable instead of a generic argument, which could mean using reflection. Sometimes it's easier to add a non-generic overload to the original class, and call it from the generic method:

    public class MyService
    {
        public void UpdateData(Type dataType, Something data, Something otherData)
        {
            // do stuff
        }
    
        public void UpdateData<T>(Something data, Something otherData)
        {
            UpdateData(typeof(T), data, otherData);
        }
    }
    

    We lose the ability to easily impose constraints on the Type argument like we could with the generic method. We can add validation if we need it.

    That gets you as close as possible to the code you're trying to write:

    _myService.UpdateData(dataType, editData, metaData);
    

    That's assuming that you find yourself still needing the generic methods at all. If you add non-generic overloads and discover that you're not calling the generic ones anymore, you can just delete them.

    A significant benefit of this over reflection is that you can identify where your code is called. A method that's only called using reflection will appear unused.