I found something quite odd(I think!). If I try to put a breakpoint in the yes() method, it will never pause the program when it executes the function. If I try to do the same to any other line of code, it will work just as expected. Is it a bug, or is there something that's escaping me?
The filter will return the 2 objects, everything seems to be working as expected except the debugger.
private void Form1_Load(object sender, EventArgs e) {
List<LOL> list = new List<LOL>();
list.Add(new LOL());
list.Add(new LOL());
IEnumerable<LOL> filter = list.Where(
delegate(LOL lol) {
return lol.yes();
}
);
string l = ""; <------this is hit by the debugger
}
class LOL {
public bool yes() {
bool ret = true; <---------this is NOT hit by the debugger
return ret;
}
}
Enumerable.Where is a lazy operator -- until you call something that goes through the IEnumerable returned by where (ie. calling .ToList() on it), your function won't get called.
Try changing your code to this and see if it gets called:
....
IEnumerable<LOL> filter = list.Where(
delegate(LOL lol) {
return lol.yes();
}
).ToList();
string l = "";
You have to materialize the list. Add a ...
filter.ToList();
... after the declaration and you will hit your breakpoint. About the best discussion I've seen on that is here. It does lazy evaluation much better justice than I could do.
As others have said, you have just defined your criteria but have not asked it for execution. This is called lazy loading (guys, correct me if I am wrong).
Run a foreach loop on filter to see what happens.
Jonathan is correct.
Try running this console application and set breakpoints where indicated to see it clearly.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<LOL> list = new List<LOL>();
list.Add(new LOL());
list.Add(new LOL());
IEnumerable<LOL> filter = list.Where(
delegate(LOL lol)
{
return lol.yes();
}
);
// Breakpoint #2 will not have been yet.
Console.Write("No Breakpoint"); // Breakpoint #1
// (Breakpoint #2 will now be hit.)
Console.Write("Breakpoint! " + filter.Count());
}
class LOL
{
public bool yes()
{
bool ret = true; // Breakpoint #2
return ret;
}
}
}
}
Related
I'm following a C#/.NET PluralSight tutorial (building a gradebook) and for some reason, my first 'Console.WriteLine(result)' isn't displaying anything when I use the "Start without Debugging" option. The second Console.WriteLine works fine.
Also, the debugger doesn't work; I set a breakpoint and the debugger runs without stopping and finishes without any errors. I'm working in Visual Studio code. Thoughts?
using System;
namespace GradeBook
{
class Program
{
static void Main(string[] args) //this is a method
{
var numbers = new[] {12.7, 10.3, 6.11, 4.1};
var result = 0.0;
foreach(double number in numbers) {
result += number;
}
Console.WriteLine(result);
if(args.Length > 0) {
Console.WriteLine($"Hello, {args[0]} !");
} else {
Console.WriteLine("Hello!");
}
}
}
}
At the end of your main method put Console.ReadKey();
I think you should put Console.ReadLine(); after the if-else statement. There's other way too, but I used to code this line.
I am trying to identify usages of the "method group" syntax in my solution. The reason is that Resharper tries to help with the ConvertClosureToMethodGroup code inspection. The problem is, that the "optimized" code does not compile to the same IL code, which means that it breaks in my specific scenario. The below scenario does not break, but it illustrates what I am trying to find:
void Main()
{
var arr = new string[]{"foo"};
//This works
var bar = arr.Select(s=>MyMethod(s));
//Resharper suggests the below, which is different
//var bar = arr.Select(MyMethod);
}
string MyMethod(string s)
{
return "bar";
}
So: Is there a way, that I can identify all the places in my code, where any method is being passed as a method group?
I can disable the refactoring suggestion to prevent future usages of this, but how can I identify the places where this already happened?
EDIT 1: Example where this refactoring breaks runtime
void Main()
{
MyClass obj = null;
//This works
var lazy = new Lazy<bool>(()=> obj.MyMethod());
//This will break at runtime when obj is null
//var lazy = new Lazy<bool>(obj.MyMethod);
}
class MyClass
{
public bool MyMethod()
{
return false;
}
}
Despite the fact, that IEnumerator.Reset method should never be used I found strange behavior of the method implementation within List<T>.
No matter how you examine the .NET Framework Source Code (tried with reference source and ILSpy) the method is implemented as following:
void System.Collections.IEnumerator.Reset() {
if (version != list._version) {
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
index = 0;
current = default(T);
}
However, it looks like the method is never called at all! Consider the code:
var list = new List<int>(1) { 3 };
using (var e = list.GetEnumerator())
{
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
((IEnumerator)e).Reset();
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
}
It's pretty clear, that it should print True and 3 twice. Instead of that the result is
True
3
False
0
Any simple explanation I'm missing?
Any simple explanation I'm missing?
Yes: you're boxing the List.Enumerator here:
((IEnumerator)e).Reset();
That takes a copy of the existing one and resets it - leaving the original in one piece.
To reset the actual enumerator, you'd need something like this:
var list = new List<int>(1) { 3 };
var e = list.GetEnumerator();
// Can't use "ref" with a using statement
try
{
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
Reset(ref e);
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
}
finally
{
e.Dispose();
}
static void Reset<T>(ref T enumerator) where T : IEnumerator
{
enumerator.Reset();
}
It's tricky because it uses explicit interface implementation.
I haven't tested it, but I think that should work for you. Obviously it's a bad idea to do this...
EDIT: Alternatively, just change your variable type to IEnumerator or IEnumerator<int> to start with. Then it will be boxed once, and the Reset method will mutate the boxed value:
var list = new List<int>(1) { 3 };
using (IEnumerator e = list.GetEnumerator())
{
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
e.Reset();
Console.WriteLine(e.MoveNext());
Console.WriteLine(e.Current);
}
I was using the same query before it was working fine. Then I decided to use complied query. So I had to make few changes to the code.
Now when I try to execute the code, I get the error message "Unsupported overload used for query operator 'Where'.
The where clause which I generate from “approvalHelper.GetWhereClauseForApprovalSimpleSearch();” has been tested and works fine.
Only doesn't work for the complied query part as shown in my code
code :
// Complied Query Class
public static class CompliedQuery
{
public static Func<GDataContext, Expression<Func<View_ApprovalSimple, bool>>, IQueryable<View_ApprovalSimple>> getApprovalSimple =
CompiledQuery.Compile<GDataContext, Expression<Func<View_ApprovalSimple, bool>>, IQueryable<View_ApprovalSimple>>(
(db, whereclause) => (from results in db.View_ApprovalSimples.AsExpandable().Where(whereclause)
select results));
}
// this is what is passed into the where clause; Body = {(vas.siteId = 1)}
//the Calling code
public static List<View_ApprovalSimple> GetApprovalSimple(ApprovalsSearchHelperClass _approvalHelper)
{
Expression<Func<View_ApprovalSimple, bool>> whrClause = approvalHelper.GetWhereClauseForApprovalSimpleSearch();
//whrclause; Body = {(vas.siteId = 1)}
try
{
using (GDataContext db = new GDataContext())
{
if (whrClause != null)
{
var varResults = CompliedQuery.getApprovalSimple(db, whrClause);
return varResults.ToList();
}
}
}
catch (Exception ex)
{
// code to handle error
}
finally
{
}
return null;
}
Any idea what new changes I might have to implement?
Thanks in advance.
Check the namespaces (start off by copying them all from CompliedQuery) to the calling class.
First I was a bit sceptical about this, ran out of options so I finally tried it and it did work.
please follow the link to see answer
Steve's Blog
Great work Steve.
I can't explain an issue I've run across. Basically I get a different answer if I use lambda syntax in a foreach loop than if I use it in a for loop. In the code below I register a delegate in a "dispatcher" class. I then later wrap the delegate on the way out in another delegate and return a list of these wrapped delegates. I then execute them. The expected output of executing the wrapped function list is 1,2. However I don't see that when I combine a lambda and a foreach loop.
This is not the code that is causing the problem, but the simplest case I could make to reproduce it. I would prefer not to discuss use cases of this, I'm more curious as to why I get behavior I'm not expecting. If I use the foreach loop below with the lambda syntax it fails. If I use the new Action() syntax and a foreach it works, if I use the lambda syntax in a for loop it works. Can anyone explain what is going on here. This has me really stumped.
public class Holder
{
public Holder(int ID, Dispatcher disp)
{
this.ID = ID;
disp.Register(Something);
}
public int ID { get; set; }
private void Something(int test) { Console.WriteLine(ID.ToString()); }
}
public class Dispatcher
{
List<Action<int>> m_Holder = new List<Action<int>>();
public void Register(Action<int> func)
{
m_Holder.Add(func);
}
public List<Action<int>> ReturnWrappedList()
{
List<Action<int>> temp = new List<Action<int>>();
//for (int i = 0; i < m_Holder.Count; i++) //Works - gives 1, 2
//{
// var action = m_Holder[i];
// temp.Add(p => action(p));
//}
foreach (var action in m_Holder)
{
temp.Add(p => action(p)); //Fails - gives 2,2
//temp.Add(new Action<int>(action)); Works - gives 1,2
}
return temp;
}
}
class Program
{
static void Main(string[] args)
{
var disp = new Dispatcher();
var hold1 = new Holder(1, disp);
var hold2 = new Holder(2, disp);
disp.ReturnWrappedList().ForEach(p => p(1));
}
}
This is the infamous "closing over the loop variable" gotcha.
Closing over the loop variable considered harmful (and part two)
Have you tried:
foreach (var action in m_Holder)
{
var a = action;
temp.Add(p => a(p));
}
This is the classic issue of a captured closure with a scope that isn't what you expect. In the foreach, the action has outer scope, so the execution captures the last value of the loop. In the for case, you create the action in inner scope, so the closure is over the local value at each iteration.