Reputation: 3573
I have strange behaviour that my code at specific place is not stepping in specific method. There is no error, no nothing. It is just reaching the line without stepping into it. I was debugging and stepping into each tep to found that issue. I have no idea what's going on, that's first time i face such an issue. Below find my code and at the end explained exactly where it happens.
static class Program
{
private static UnityContainer container;
[STAThread]
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
Application.Run(container.Resolve<FrmLogin>());
}
private static void Bootstrap()
{
container = new UnityContainer();
container.RegisterType<IRepositoryDal<User>, UserRepositoryDal>();
container.RegisterType<IRepositoryDal<Order>, OrderRepositoryDal>();
container.RegisterType<IDbManager, DbManager>(new InjectionConstructor("sqlserver"));
container.RegisterType<IGenericBal<User>, UserBal>();
container.RegisterType<IGenericBal<Order>, OrderBal>();
}
}
public partial class FrmLogin : Form
{
private readonly IGenericBal<User> _userBal;
public FrmLogin(IGenericBal<User> userBal)
{
InitializeComponent();
_userBal = userBal;
}
private void btnSearch_Click(object sender, EventArgs e)
{
try
{
var a = _userBal.SearchByName("John");
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
public class UserBal : IGenericBal<User>
{
private readonly IRepositoryDal<User> _userRepositoryDal;
public UserBal(IRepositoryDal<User> userRepositoryDal)
{
_userRepositoryDal = userRepositoryDal ?? throw new ArgumentNullException(nameof(userRepositoryDal));
}
public IEnumerable<User> SearchByName(string name)
{
return _userRepositoryDal.SearchByName(name);
}
}
public interface IGenericBal<out T> where T : IEntity
{
IEnumerable<T> SearchByName(string name);
}
public class UserRepositoryDal: IRepositoryDal<User>
{
private readonly IDbManager _dbManager;
public UserRepositoryDal(IDbManager dbManager)
{
_dbManager = dbManager;
}
public IEnumerable<User> SearchByName(string username)
{
var parameters = new List<IDbDataParameter>
{
_dbManager.CreateParameter("@Name", 50, username, DbType.String),
};
username = "JUSTyou";
var userDataTable = _dbManager.GetDataTable("SELECT * FROM T_Marke WHERE Name=@Name", CommandType.Text, parameters.ToArray());
foreach (DataRow dr in userDataTable.Rows)
{
var user = new User
{
Id = int.Parse(dr["Id"].ToString()),
Firstname = dr["Name"].ToString(),
};
yield return user;
}
}
}
public interface IRepositoryDal<T> where T : IEntity
{
IEnumerable<T> SearchByName(string username);
T SearchById(string id);
void Update(T entity);
void Remove(T entity);
void Add(T entity);
}
What happens here is:
When i start to debug using breakpoints i start to click button which raises btnSearch_Click
handler you can find in my code. When it happens it goes to: var a = _userBal.SearchByName("John");
then to UserBal
's code SearchByName
method. When it reaches: return _userRepositoryDal.SearchByName(name);
it's not going into in this case UserRepositoryDal
's SerachByName
method. It's just highlight this line of code and going next but not inside. No error, no nothing... Why it happens?
Upvotes: 1
Views: 151
Reputation: 1317
This is called "Lazy evaluation": https://blogs.msdn.microsoft.com/pedram/2007/06/02/lazy-evaluation-in-c/
In brief, you use yield return
to return the method's results, which means that the code does not get evaluated immediately, but the actual method execution gets postponed up to until you actually use some results of the evaluation.
Update:
If you want to evaluate your code immediately, you need to use it somehow. The simplest way would be to return the whole result set to create a new array or list from it. You can do it, for instance, by replacing:
return _userRepositoryDal.SearchByName(name);
with:
return _userRepositoryDal.SearchByName(name).ToList();
While this might be good for debugging, it will also remove the performance gains you obtain by using lazy evaluation.
Upvotes: 5
Reputation: 29760
This bit of code is an Lazy Enumeration:
public IEnumerable<User> SearchByName(string username)
{
var parameters = new List<IDbDataParameter>
{
_dbManager.CreateParameter("@Name", 50, username, DbType.String),
};
username = "JUSTyou";
var userDataTable = _dbManager.GetDataTable("SELECT * FROM T_Marke WHERE Name=@Name", CommandType.Text, parameters.ToArray());
foreach (DataRow dr in userDataTable.Rows)
{
var user = new User
{
Id = int.Parse(dr["Id"].ToString()),
Firstname = dr["Name"].ToString(),
};
yield return user;
}
}
By using yield return user;
your telling .Net to only run this code when it's enumerated. At no point are you accessing the result of SearchByName
. So it won't step into it:
public IEnumerable<User> SearchByName(string name)
{
//this doesn't access the result
return _userRepositoryDal.SearchByName(name);
//this would
//return _userRepositoryDal.SearchByName(name).ToList();
}
The easiest way to "fix" this is to remove the enumeration as I don't think this is what you want:
public IEnumerable<User> SearchByName(string username)
{
List<User> response = new List<User>();
var parameters = new List<IDbDataParameter>
{
_dbManager.CreateParameter("@Name", 50, username, DbType.String),
};
username = "JUSTyou";
var userDataTable = _dbManager.GetDataTable("SELECT * FROM T_Marke WHERE Name=@Name", CommandType.Text, parameters.ToArray());
foreach (DataRow dr in userDataTable.Rows)
{
var user = new User
{
Id = int.Parse(dr["Id"].ToString()),
Firstname = dr["Name"].ToString(),
};
//Add to a collection
response.Add(user);
}
//return result
return response;
}
Upvotes: 2