Метод расширения, который возвращает базовый тип аргумента generi c - PullRequest
2 голосов
/ 01 мая 2020

Я пытаюсь написать метод расширения IThingRequest<TEntity>, он возвращает Thing<TEntity>. Мне бы хотелось, чтобы метод возвращал только базовый тип TEntity, а не любые другие обобщенные c классы или интерфейсы, которые он реализовывал. Итак, в приведенном ниже примере wi sh состоит в том, что тип возвращаемого значения должен быть Thing<Entity>, а не Thing<GenericClass<Entity>>.

Метод расширений:

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

Вызов метода расширения :

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

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

Тип результата теперь Thing<GenericClass<Entity>>.

Мой первый инстинкт был в том, что был бы способ достичь этого с помощью where, но я не могу понять это из. Я также подумал об использовании отражений, чтобы получить * generic c тип TEntity и вернуть Thing<object>, но я считаю, что это потребует приведения при использовании метода DoStuff.

Любая помощь с благодарностью!

Ответы [ 3 ]

1 голос
/ 01 мая 2020

Спасибо за все введенные данные!

Я хотел найти решение, в котором мне не нужно было преобразовывать результат из DoStuff в Thing<TEntity>, как, например, приведение object. Благодаря @Charleh я понял, что решил проблему неправильно, и решение состояло в том, чтобы просто реализовать и класс, и интерфейс отдельно, вот так:

public class Request : GenericClass<TEntity>, IThingRequest<Entity>
{ }
0 голосов
/ 01 мая 2020

вижу следующий вариант решения. GenericClass должен реализовывать IThingRequest. Тогда метод расширения DoStuff можно сделать рефлексивно рекурсивным:

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
    {
    }
}
0 голосов
/ 01 мая 2020

Если вы хотите работать с вложенными генериками и знаете «обертку», вам нужно что-то вроде этого:

public static Thing<T2> UnWrap<T1, T2>(IThingRequest<T1> request) 
       where T1: GenericClass<T2>
=> new Thing<T2>();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...