-1

I have this code Linq c#

from r in Employer.Restrictions 
select new RestrictionDto(r);

The employer restrictions have on register but the constructor of RestrictionDto is never called and just return null. I put a breakPoint in restrictionDto and the code never stop.

I never saw this problem before. I have many codes like that in the code and work fine.

someone can help?

Paulo
  • 577
  • 3
  • 8
  • 23
  • 3
    Are you using the query somewhere subsequent to creating it? Linq queries aren't evaluated until they are used. – Diado Dec 20 '18 at 13:16
  • yes, Employer.Restrictions have elements. yes, Constructor of RestrictionDto accept argument correct. ANd yes, I check with "ToList" if have any result – Paulo Dec 20 '18 at 13:17
  • 2
    This wasn´t the question. The question is where you´re using the results of the query. – MakePeaceGreatAgain Dec 20 '18 at 13:19
  • I understand that it has elements, but are you actually referencing the query after you have created it? By iterating over the resultset, or calling `.ToList()` for instance? It won't be evaluated until you do so. – Diado Dec 20 '18 at 13:19
  • Might be [useful](https://stackoverflow.com/q/3894490/1997232) and specifically for [ef](https://stackoverflow.com/q/30624700/1997232). – Sinatr Dec 20 '18 at 13:21

2 Answers2

5

Linq queries are lazy, i.e. they don't actually perform anything until told otherwise.

In other words, you're not asking for the execution of the query. if you want to execute the query, it has to finish with ToList or whatever eager operation you feel is appropriate for the task at hand.

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
  • maybe I'm not clear. The result is a Linq result, but when I tried call toList, the result is Null and never call the constructor – Paulo Dec 20 '18 at 13:20
  • 4
    @Paulo `ToList` would never return null. further, if the constructor is never called then that means `Employer.Restrictions ` is empty. maybe you should first check if the source is empty or not? if it's not and you're _definitely_ calling `ToList` I don't see any reason why it wouldn't work... – Ousmane D. Dec 20 '18 at 13:24
2

You have to be aware that there are two kinds of LINQ statements:

  • those that return IEnumerable<...> (or IQueryable)
  • and those that don't.

The first group will only return an object that contains everything that is needed to enumerate the elements: get the first element of the sequence, and once you've got one, you can get the next one, until there are no more left.

Note: by creating this enumerable object, you haven't enumerated it yet.

The second group, the LINQ functions that don't return IEnumerable<...> are the ones that will actually start enumerating: ToList, ToDictionary, FirstOrDefault, Count, Max, Any.

These function use the input IEnumerable to call GetEnumerator() and repeatedly call MoveNext() until they know the return value. Quite often the complete sequence needs to be enumerated, sometimes only a few of them.

For example:

public static bool Any<TSource>(this IEnumerable<Tsource> source)
{
     if (source == null) throw new ArgumentNullException(...);
     IEnumerator<TSource> enumrator = source.GetEnumerator();
     bool containsAnyElement = enumerator.MoveNext();

     // no need to check the rest of the sequence, I already know the result:
     return containsAnyElement;
}

Back to your question

Your code creates an IEnumerable<...> It is similar to:

IEnumerable<RestrictionDto> restrictions = Employer.Restrictions
    .Select(restriction => new RescrictionDto(restriction));

In words: make an enumerable object, that, when enumerated, will return one new object RestrictionDto per MoveNext that is called on the enumerator, for every restriction in the enumerable sequence Employer.Restrictions.

So you have created the Enumerable object, but you haven't enumerated over it yet.

Try the following, your debugger will show you that your RestrictionDtos are actally created:

var list = restrictions.ToList();
bool restrictionsAvailable = restrictions.Any();
var firstRestriction = restrictions.FirsOrDefault();
int numberOfRestrictions = restrictions.Count();
foreach (var restiction in restrictions)
{
    ...
}

They will all internally do something similar to the following:

var enumerator = restrictions.GetEnumerator();
while(enumerator.MoveNext())
{   // there are still restrictions left
    RestrictionDto restriction = enumerator.Current;
    // do something with this restriction
}
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116