基于接口实现的LINQ连接

时间:2018-10-01 10:58:27

标签: c# linq interface

比方说,我有一个接口,它基本上是两个子接口的组合。其背后的想法是,我有两个不同的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 :(得分:4)

假设您编写了一种方法,例如:

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))

答案 1 :(得分:3)

问题不在Join中,而是在您要返回的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;
     }
}

此对象不需要复制特殊数据和秘密人员数据的值。但是请记住,如果更改值,则原始数据也会更改。如果您不想这样做,则在创建对象时需要复制数据

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,
    });

答案 2 :(得分:0)

LINQ的Join method为您完成这项工作。假设有一个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));
}