LINQ соединение основано на реализации интерфейса - PullRequest
0 голосов
/ 01 октября 2018

Допустим, у меня есть интерфейс, который в основном представляет собой комбинацию двух подчиненных интерфейсов.Идея заключается в том, что у меня есть два разных API.Тот, который предоставляет публичную информацию о человеке.И один раз, который предоставляет «секретную» информацию.Это может выглядеть примерно так:

public interface IPublicPersonData
{
    // The ID is the key
    int PersonId { get; set; }

    // This property is specific to this part
    string Name {get; set; }
}

public interface ISecretPersonData
{
    // The ID is the key
    int PersonId { get; set; }

    // This property is specific to this part
    decimal AnnualSalary{ get; set; }
}

public interface IPerson: IPublicPersonData, ISecretPersonData
{
    // No new stuff, this is merely a combination of the two. 
}

Так что в основном я получаю два списка.Один List<IPublicPersonData> и один List<ISecretPersonData>.Я хотел бы объединить их в один List<IPerson>, в идеале используя LINQ.

Я не могу найти ничего о том, как управлять типом вывода из LINQ, основываясь на типе вводадаже если есть логика (в виде интерфейсов, реализующих интерфейсы).

public List<IPerson> JoinPersonData(
    List<IPublicPersonData> publicData, 
    List<ISecretPersonData> secretData)
{
    // What the heck goes here?
}

Ответы [ 3 ]

0 голосов
/ 01 октября 2018

LINQ's Метод соединения сделает всю работу за вас.Предполагая, что существует класс Person : IPerson, есть два способа реализации вашего метода JoinPersonData:

public static IEnumerable<IPerson> LiteralJoinPersonData(List<IPublicPersonData> publics, List<ISecretPersonData> secrets)
{
    return from p in publics
           join s in secrets on p.PersonId equals s.PersonId
           select new Person(p.PersonId, p.Name, s.AnnualSalary);
}

public static IEnumerable<IPerson> FunctionalJoinPersonData(List<IPublicPersonData> publics, List<ISecretPersonData> secrets)
{
    return publics
        .Join<IPublicPersonData, ISecretPersonData, int, IPerson>(
            secrets,
            p => p.PersonId,
            s => s.PersonId,
            (p, s) => new Person(p.PersonId, p.Name, s.AnnualSalary));
}
0 голосов
/ 01 октября 2018

Проблема не в присоединении, а в IPerson, которого вы хотите вернуть.Один из параметров методов Join используется, что делать с объединенным результатом.

Вы хотите объединить их в новый объект, который реализует IPerson.Если у вас уже есть такой объект: отлично, используйте его, если у вас его нет, вот простой:

public PersonData : IPerson // and thus also IPublicPersonData and ISecretPersonData
{
     // this PersonData contains both public and secret data:
     public IPublicPersonData PublicPersonData {get; set;}
     public ISecretPersnData SecretPersonData {get; set;}


     // implementation of IPerson / IPublicPersonData / ISecretPersonData
     int PersonId
     { 
         get {return this.PublicPersonData.Id; }
         set
         {   // update both Ids
             this.PublicPersonData.Id = value;
             this.SecreatPersonData.Id = value;
         }
     }
     public string Name
     {
        get { return this.PublicPersonData.Name; },
        set {this.PublicPersonData.Name = value;}
     }

     public decimal AnnualSalary
     {
         get {return this.SecretPersonData.AnnualSalary;},
         set {this.SecretPersnData.AnnualSalary = value;
     }
}

Этот объект не требует копирования значений puclic и secretличные данные.Имейте в виду, однако, что при изменении значений исходные данные изменяются.Если вы не хотите этого, вам нужно будет скопировать данные при создании объекта

IEnumerable<IPublicPersonData> publicData = ...
IEnumerable<ISecretPersonData> secretData = ...

// Join these two sequences on same Id. Return as an IPerson
IEnumerable<IPerson> joinedPerson = publicData       // take the public data
    .Join(secretData,                                // inner join with secret data
    publicPerson => publicPerson.Id,                 // from every public data take the Id
    secretPerson => secretPerson.Id,                 // from every secret data take the Id
    (publicPerson, secretPerson) => new PersonData() // when they match make a new PersonData
    {
         PublicPersonData = publicPerson,
         SecretPersnData = secretPerson,
    });
0 голосов
/ 01 октября 2018

Скажем, вы написали такой метод, как:

public ISomething CombinePersonWithSecret(
    IPublicPersonData publicPerson, 
    ISecretPersonData secret)
{
    if(publicPerson.PersonId != secret.PersonId)
    {
        throw ...;
    }
    //join 2 params into a single entity
    return something;
}

Теперь вы можете ...

IEnumerable<ISomething> secretivePeople = PublicPeople.Join(
    SecretPersonData,
    publicPerson => publicPerson.PersonId,
    secret => secret.PersonId,
    (publicPerson, secret) => CombinePersonWithSecret(publicPerson, secret))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...