简体   繁体   中英

Extension method that returns underlying type of generic argument

I'm trying to write a extension method of IThingRequest<TEntity> , it returns Thing<TEntity> . I would like the method to only return the underlying type of TEntity not any other generic classes or interfaces it would implement. So, in the example below, the wish is that the return type should be Thing<Entity> not Thing<GenericClass<Entity>> .

The extensions method:

public static Thing<TEntity> DoStuff<TEntity>(IThingRequest<TEntity> request)
    => new Thing<TEntity>();

Calling the extension method:

public class Request : IThingRequest<GenericClass<Entity>>
{ }

var request = new Request();
var result = request.DoStuff();

The type of result is now Thing<GenericClass<Entity>> .

My first instinct was that there would be a way to achieve this with where , but I can't figure it out. I've also considered using reflections to get the non generic type of TEntity and returning Thing<object> but I believe that that would require casting where the DoStuff method is used.

Any help is greatly appreciated!

Thanks for all the input!

I wanted a solution where I didn't have to cast the result from DoStuff into Thing<TEntity> , like for instance casting object . Thanks to @Charleh I realised I was tackling the problem wrong and the solution was simply to implement both the class and interface separately like so:

public class Request : GenericClass<TEntity>, IThingRequest<Entity>
{ }

If you want to handle nested generics and you know "wrapper" one you need to something like this:

public static Thing<T2> UnWrap<T1, T2>(IThingRequest<T1> request) 
       where T1: GenericClass<T2>
=> new Thing<T2>();

I see following variant of solution. GenericClass should implement IThingRequest. Then DoStuff extension method can be made reflectively recursive:

using System;
using System.Reflection;

namespace ConsoleApp1
{
    static class Program
    {
        static void Main(string[] args)
        {
            var request = new Request();
            var result = request.DoStuff();
            Console.ReadKey();
        }

        private static MethodInfo _doStaffMethodInfo;
        public static MethodInfo DoStaffMethodInfo => _doStaffMethodInfo = _doStaffMethodInfo ?? typeof(Program).GetMethod("DoStuff");

        public static object DoStuff<TEntity>(this IThingRequest<TEntity> request)
        {
            Type underlyingTypeOfTEntity = typeof(TEntity).GetInterface("IThingRequest`1")?.GenericTypeArguments[0];
            if (underlyingTypeOfTEntity != null)
            {
                MethodInfo doStaffMethodInfo = DoStaffMethodInfo.MakeGenericMethod(underlyingTypeOfTEntity);
                object thingRequest = Activator.CreateInstance(typeof(ThingRequest<>).MakeGenericType(underlyingTypeOfTEntity));
                return doStaffMethodInfo.Invoke(null, new []{thingRequest});
            }
            else
            {
                return new Thing<TEntity>();
            }
        }
    }

    public interface IThingRequest<TEntity>
    {

    }

    public class GenericClass<TEntity> : IThingRequest<TEntity>
    {
    }

    public class Thing<TEntity>
    {
    }

    public class ThingRequest<TEntity> : IThingRequest<TEntity>
    {

    }

    public class Request : IThingRequest<GenericClass<Entity>>
    { }

    public class Entity
    {
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM