Создать метод Generi c в классе потребителей репозитория generi c - PullRequest
1 голос
/ 20 июня 2020

Я хочу создать общий c метод в generi c классе потребителя репозитория.

Вот мой общий c метод в generi c классе репозитория:

public class CosmosDBRepository<T> : ICosmosDBRepository<T> where T : class
    {
     public async Task<IEnumerable<T>> GetItemsAsync(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByDesc, int takeCount = -1)
    
            {
                var criteria = _container.GetItemLinqQueryable<T>(true)
                    .Where(predicate)
                    .OrderByDescending(orderByDesc)
                    .ToFeedIterator();
    
                var query = criteria;
    
                var results = new List<T>();
                while (query.HasMoreResults)
                {
                    if (takeCount > -1 && results.Count >= takeCount) break;
                    results.AddRange(await query.ReadNextAsync());
                }
    
                return results;
            }
}

Generi c Класс потребителя репозитория:

 public class SubscriptionRepository : CosmosDBRepository<Subscription>, ISubscriptionRepository
    {
        public SubscriptionRepository(
            ICosmosDBClient client
            ) : base(client)
        {

        }

        
        public async Task<List<T>> GetSubscriptions<T, TE>(
            TE eventItem,
            params SubscriptionAction[] subscriptionAction)
                where T : Subscription
                where TE : Event
        {
            Expression<Func<T, bool>> predicate = (x) => x.EventType == eventItem.EventType
                            && x.IsActive;

            predicate = predicate.And(x => subscriptionAction.Contains(x.Action));

            if (!string.IsNullOrEmpty(eventItem.PayerNumber))
            {
                predicate = predicate.And(x => x.PayerNumber == eventItem.PayerNumber);
            }
            else if (!string.IsNullOrEmpty(eventItem.AccountNumber))
            {
                predicate = predicate.And(x => x.AccountNumber == eventItem.AccountNumber);
            }

            var result = await GetItemsAsync(predicate, o => o.PayerNumber);

            return result.ToList();
        }
    }

Теперь я хочу создать generi c метод GetSubscriptions в SubscriptionRepository классе.

Не могли бы вы подсказать, как я может достичь этого?

В настоящее время я получаю следующую ошибку времени компиляции:

не удается преобразовать из 'System.Linq.Expression > 'в' System.Linq.Expression.Expression > '

Ответы [ 2 ]

1 голос
/ 20 июня 2020

Здесь есть как минимум две проблемы, обе одинаковой природы - вы пытаетесь создать общий метод c для обертывания конкретной CosmosDBRepository<Subscription>.GetItemsAsync функции. Сначала можно решить, изменив предикат на:

Expression<Func<Subscription, bool>> predicate = x => x.EventType == eventItem.EventType && x.IsActive; 

Но это не решит проблему, заключающуюся в том, что CosmosDBRepository<Subscription>.GetItemsAsync вернет коллекцию Subscription, а не коллекцию произвольных Subscription потомков. Если вам нужно GetSubscriptions по-прежнему быть generi c, вам нужно будет либо отфильтровать и преобразовать результат GetItemsAsync:

return result.OfType<T>().ToList();

, либо предоставить функцию сопоставления для метода:

 public async Task<List<T>> GetSubscriptions<T, TE>(
        TE eventItem,
        Func<Subscription, T> mapper, 
        params SubscriptionAction[] subscriptionAction)
            where T : Subscription
            where TE : Event
    {
        .....
        return result.Select(mapper).ToList();
    }
 
0 голосов
/ 20 июня 2020

Возможно, вам следует использовать

Expression<Func<Subscription, bool>> predicate = (x) => x.EventType == eventItem.EventType
                        && x.IsActive;

Поскольку вы используете общий c тип T вместо подписки (даже если вы проверяете, что T должен быть подпиской или дочерним классом), выражение не может

И в вашем случае я не вижу преимуществ использования generi c в GetSubscriptions вместо реального типа напрямую.

Посмотрите этот пример:

   public class Test
   {
   }

   Expression<Func<Test, bool>> temp1 = (t) => true;
   Expression<Func<object, bool>> temp2 = temp1;

Этот пример завершится ошибкой во второй строке. Даже Test является дочерним классом объекта (как и весь класс в. NET)

Edit

Как объяснено здесь: https://docs.microsoft.com/en-us/dotnet/api/system.func-2?view=netcore-3.1

T of Fun c (первый параметр обобщенного типа c) имеет ключевое слово «in». Это означает:

Этот параметр типа контравариантен. То есть вы можете использовать либо указанный вами тип, либо любой менее производный тип.

Так как T может быть дочерним по отношению к Subscription (скажем, «ChildSubscription»). Когда вы пытаетесь назначить Fun c на Fun c, ваша попытка назначить более производное.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...