Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will passing `this` inside of a `.Where` clause's predicate cause it to mutate?

Using Entity Framework, and wrapping a DbContext in a class like this:

public class Demo : IDisposable
{
  internal DbContext context;
  internal int PrivateId = 5;      

  public Demo()
  {
   this.context = new MyDbContext();
  }
  public void Question()
  {
   //Is there going to be a problem using `this` in the predicate
   var issue = this.context.SomeTable.Where(st => st.ForeignKeyId == this.PrivateId);
  }
  public Dispose()
  {
   this.context.Dispose();
  }
}

This is as simple of a demo as I could come up with. I was unsure if this would somehow be changed or modified when used as part of the predicate to Where. Basically I just wanted to double check because I was uncertain. I checked out Jon Skeet's re-implementation of Where but it was still not entirely clear that this would retain its value.

My uncertainty stems from the issue that predicates are passed as Func when used with deferred execution. As a result, it would seem that the reference for this could be used at a later time instead of immediately when Where is called.

Am I over-thinking the situation, or is there a possibility of this changing?

like image 465
Travis J Avatar asked Dec 20 '22 18:12

Travis J


1 Answers

this is read-only (for reference types). You can't change what reference this refers to. The object that the reference stored in this variable refers to may in fact change over time.

So you can be sure that, for that code, whenever it is in fact executed it will use the current instance of the object, and that you won't end up referencing some entirely different Demo object. It will then go to that instance and pick up the value of it's PrivateId variable at that instant in time. So if PrivateId has changed for that particular instance, then the changed value is what is used.

This has nothing at all to do with the implementation of Where, but rather the semantics of reference types and the whole concept of deferred execution.

If you want to use the value of PrivateId right now, not when the sequence is actually iterated, then simply copy the value of that variable out into some new variable and close over that, like so:

var idCopy = this.PrivateId;
var issue = this.context.SomeTable.Where(st => st.ForeignKeyId == idCopy );
like image 186
Servy Avatar answered Mar 08 '23 23:03

Servy