Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 707625
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 14, 20262026-05-14T04:17:57+00:00 2026-05-14T04:17:57+00:00

I’m writing a data access layer. It will have C# 2 and C# 3

  • 0

I’m writing a data access layer. It will have C# 2 and C# 3 clients, so I’m compiling against the 2.0 framework. Although encouraging the use of stored procedures, I’m still trying to provide a fairly complete ability to perform ad-hoc queries. I have this working fairly well, already.

For the convenience of C# 3 clients, I’m trying to provide as much compatibility with LINQ query syntax as I can. Jon Skeet noticed that LINQ query expressions are duck typed, so I don’t have to have an IQueryable and IQueryProvider (or IEnumerable<T>) to use them. I just have to provide methods with the correct signatures.

So I got Select, Where, OrderBy, OrderByDescending, ThenBy, and ThenByDescending working. Where I need help are with Join and GroupJoin. I’ve got them working, but only for one join.

A brief compilable example of what I have is this:

// .NET 2.0 doesn't define the Func<...> delegates, so let's define some workalikes
delegate TResult FakeFunc<T, TResult>(T arg);
delegate TResult FakeFunc<T1, T2, TResult>(T1 arg1, T2 arg2);

abstract class Projection{
    public static Condition operator==(Projection a, Projection b){
        return new EqualsCondition(a, b);
    }
    public static Condition operator!=(Projection a, Projection b){
        throw new NotImplementedException();
    }
}
class ColumnProjection : Projection{
    readonly Table  table;
    readonly string columnName;

    public ColumnProjection(Table table, string columnName){
        this.table      = table;
        this.columnName = columnName;
    }
}
abstract class Condition{}
class EqualsCondition : Condition{
    readonly Projection a;
    readonly Projection b;

    public EqualsCondition(Projection a, Projection b){
        this.a = a;
        this.b = b;
    }
}
class TableView{
    readonly Table        table;
    readonly Projection[] projections;

    public TableView(Table table, Projection[] projections){
        this.table       = table;
        this.projections = projections;
    }
}
class Table{
    public Projection this[string columnName]{
        get{return new ColumnProjection(this, columnName);}
    }

    public TableView Select(params Projection[] projections){
        return new TableView(this, projections);
    }
    public TableView Select(FakeFunc<Table, Projection[]> projections){
        return new TableView(this, projections(this));
    }
    public Table     Join(Table other, Condition condition){
        return new JoinedTable(this, other, condition);
    }
    public TableView Join(Table inner,
                          FakeFunc<Table, Projection> outerKeySelector,
                          FakeFunc<Table, Projection> innerKeySelector,
                          FakeFunc<Table, Table, Projection[]> resultSelector){
        Table join = new JoinedTable(this, inner,
            new EqualsCondition(outerKeySelector(this), innerKeySelector(inner)));
        return join.Select(resultSelector(this, inner));
    }
}
class JoinedTable : Table{
    readonly Table     left;
    readonly Table     right;
    readonly Condition condition;

    public JoinedTable(Table left, Table right, Condition condition){
        this.left      = left;
        this.right     = right;
        this.condition = condition;
    }
}

This allows me to use a fairly decent syntax in C# 2:

Table table1 = new Table();
Table table2 = new Table();

TableView result =
    table1
    .Join(table2, table1["ID"] == table2["ID"])
    .Select(table1["ID"], table2["Description"]);

But an even nicer syntax in C# 3:

TableView result =
    from t1 in table1
    join t2 in table2 on t1["ID"] equals t2["ID"]
    select new[]{t1["ID"], t2["Description"]};

This works well and gives me identical results to the first case. The problem is if I want to join in a third table.

TableView result =
    from t1 in table1
    join t2 in table2 on t1["ID"] equals t2["ID"]
    join t3 in table3 on t1["ID"] equals t3["ID"]
    select new[]{t1["ID"], t2["Description"], t3["Foo"]};

Now I get an error (Cannot implicitly convert type ‘AnonymousType#1’ to ‘Projection[]’), presumably because the second join is trying to join the third table to an anonymous type containing the first two tables. This anonymous type, of course, doesn’t have a Join method.

Any hints on how I can do this?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-14T04:17:57+00:00Added an answer on May 14, 2026 at 4:17 am

    This is a very interesting design, I like it!
    As you’re saying, the problem is that your definition of the Join method is too specific. The key difference between your definition and the one in LINQ is following:

    public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(
        /* cut */, Func<TOuter, TInner, TResult> resultSelector)
    
    public TableView Join(
         /* cut */, FakeFunc<Table, Table, Projection[]> resultSelector)
    

    When LINQ compiles a query with multiple join clauses, it calls them in a sequence and it generates resultSelector for the first one automatically – and the generated code returns a simple anonymous type containing the elements from both of the source tables. So, if I’m correct, in your case, the generated anonymous type would look like this:

    new { t1 : Projection; t2 : Projection }
    

    This is unfortunately incompatible with Projection[] (even though semantically, the difference isn’t big). I’m afraid that the only way to solve this would be to use dynamic type casts and Reflection.

    • You need to modify Join so that it has generic type parameter TResult used in the resultSelector.

    • In the Join method you’d run TResult res = resultSelector(...) and then you need to do something with the res value.

    • If res is Projection[] then you can use your existing code (this is the case that will be used in a query that contains a single join clause)

    • In the other case, res is an anonymous type like the one above. This means that you’ll need to use reflection to get values of the properties of the type and turn them into an array of Projection values (and then do the same thing as you’re doing now).

    I didn’t try implementing that, but I think it may work…

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Ask A Question

Stats

  • Questions 374k
  • Answers 374k
  • Best Answers 0
  • User 1
  • Popular
  • Answers
  • Editorial Team

    How to approach applying for a job at a company ...

    • 7 Answers
  • Editorial Team

    What is a programmer’s life like?

    • 5 Answers
  • Editorial Team

    How to handle personal stress caused by utterly incompetent and ...

    • 5 Answers
  • Editorial Team
    Editorial Team added an answer If you use the QGraphicsItem::pos(), it gives you the position… May 14, 2026 at 7:48 pm
  • Editorial Team
    Editorial Team added an answer Set error reporting to all and you will get info… May 14, 2026 at 7:48 pm
  • Editorial Team
    Editorial Team added an answer To further Chad's comment, your code would require both strings… May 14, 2026 at 7:48 pm

Trending Tags

analytics british company computer developers django employee employer english facebook french google interview javascript language life php programmer programs salary

Top Members

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.