-1

I'm trying to better understand lambda expressions with generic methods, I have some code for opening a connection and getting some information from a session I frequently use.

My goal is to pass in a object of Type T which can then get data from the fixture inside the lambda expression.

 protected T getDataFromFixture<T>(int fixture_id, TTFixture fixture, Func<T, T> lambda)
 {
     var fixtures = Session.AllFixtures;
     fixture = fixtures.ContainsKey(fixture_id) ? fixtures[fixture_id] : null;
     if (fixture != null)
     {
          return lambda(T);
     } 
     return default(T);
 } 

Question is: How do I pass through a lambda function into the openConnectionWithFixtureObject which can access the fixture object and return as type T

something like..

string total;
TTFixture fixture;
openConnectionWithFixtureObject<StatTotalList>(_fixtureUid, fixture, (statTotalsForOverview) => 
{
    total; = fixture.myTotal();
});

I don't think the logic is too far off, i'm just unfamiliar with Func<T,TResult> and generics . Any assistance would be greatly appreciated!

Tolga Evcimen
  • 7,112
  • 11
  • 58
  • 91
Tim Kalinowski
  • 306
  • 5
  • 18
  • 1
    What is the question? – roydukkey May 30 '14 at 04:30
  • 1
    I'm confused but your `lambda` parameter is of type `Func` meaning it returns object. Therefore your whole function needs to return `object`, and not `T`? Although honestly I don't know what `lambda` is even supposed to do or why it's part of the function. – lc. May 30 '14 at 04:31
  • You need to tell us what `lambda` is supposed to do. You can't pass `T` to it. Do you instead want to pass `fixture` to it and have it return an object of type `T`? – Jim Mischel May 30 '14 at 04:36
  • the lambda parameter is intended to be a function passed into the method with its own parameter of an instance of the type T object. The passed in type T object (in the example statTotalsForOverview ) can then copy data from fixture in the function. apologies for the lack of clarity, the example is more so for trying to get my head around the concept as I try and understand the generics, delegation and lambda concepts. – Tim Kalinowski May 30 '14 at 04:43
  • Nothing really looks wrong syntactically, however it really hard to provide any feedback because all the objects are custom and (we) don't have documentation associated. – roydukkey May 30 '14 at 04:43
  • Okay thanks, cleaned up the example and removed references to code outside of the question. – Tim Kalinowski May 30 '14 at 04:50

1 Answers1

1

I don't think there is anything inherently wrong with the approach, but there are some problems with the implementation in the post - mainly, it is not well-typed and will not compile.

Consider this updated version with notes

protected T openConnectionWithFixtureObject<T>(
    int fixture_id, /* #1 */ Func<T, T> decorate) 
    where T : class /* for #3 */
{
     // ..
     var fixtures = MyMobileSession.Current.MyClub.MySport.AllFixtures;
     T fixture = fixtures.ContainsKey(fixture_id)
         ? fixtures[fixture_id] as T  /* #3 */
         : null;
     if (fixture != null)
     {
       /* #2 */
       return decorate(fixture);
     }
     // ..
}

openConnectionWithFixtureObject<StatTotalList>(_fixtureUid, /* #1 */
    /* #4 */
    (statTotalsForOverview) => {
        statTotalsForOverview.total = fixture.myTotal();
        return statTotalsForOverview;
    });
  1. Removed the TTFixture fixture parameter/argument, because it made no sense with the ID lookup-up and would result in an error due to a re-declaration of fixture.

  2. The fixture expression needs to be typed as T so that it can be passed to Func<T,..>. In this case the as operator can be used - if the found value is not assignable, fixture will be null. (Alternatively, a cast-and-guard could have been used without adding a class restriction on T.)

  3. A Func<T,..> accepts an argument of type T. However, T is itself simply a generic parameter and not a value of type T. As such, lambda(T) in the original code did not make sense. The solution is to use an actual (fixture) object/value.

  4. The function accepts a Func<T,T> and not an Action<T>. The inclusion of the return keyword in the lambda syntax makes it result in a function. However, it likely makes more sense to accept an Action<T> from the start, unless the function can return a different object.

Also, in C# "Lambda [Expressions]" refers to the syntax used to created the corresponding Action-Func-Expression-etc value - but beyond that there is no "lambda type".

user2864740
  • 60,010
  • 15
  • 145
  • 220
  • Thanks for making sense of what I was trying to accomplish, this has really helped me understand the concepts better. Small question, what do you mean by cast-and-guard? cheers! – Tim Kalinowski May 30 '14 at 05:07
  • @TimKalinowski `bool valid; T fixture = default(T); try { fixture = (T)raw_fixture; valid = true; } catch (InvalidCastException) { valid = false; }; if (valid) { .. }` - Then the T parameter doesn't have to be restricted to classes (Reference Types), although it likely makes sense to keep such a restriction and, if so, `as` is cleaner/shorter. – user2864740 May 30 '14 at 05:16
  • @TimKalinowski It might even make more sense to restrict T to some sentinel, e.g. an `IFixture`. – user2864740 May 30 '14 at 05:18
  • Ace that was my assumption, i'll stick with `where T : Class` and `as` appreciate the clarification. – Tim Kalinowski May 30 '14 at 05:18