473,396 Members | 2,033 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Anonymous type and 'if' statements

Is there any way I can avoid the ugly and repetitive 'if' construct shown
below?

I can't refactor into a separate method because qryTrans is an anonymous type.

I don't think I can use a switch statement either.

It works fine but is not aesthetically pleasing!

private void btnSearch_Click(object sender, EventArgs e)
{
qryStart = dtmpickStart.Value;
qryEnd = dtmpickEnd.Value;

var qryTrans =
from trans in dataSet.Transaction // get data for all
transactions
where ((trans.T_Date >= qryStart) // between start and end
dates
&& (trans.T_Date <= qryEnd))
select new
{
trans.T_Date,
trans.T_PayeeId,
trans.T_Category,
trans.T_SubCategory,
trans.T_PayMethod,
trans.T_Amount
};

// if Payee and Category selected, get transactions for both
if ((chkbxPayee.Checked) && (chkbxCategory.Checked))
{
if (!string.IsNullOrEmpty(qryPayeeId))
qryTrans =
qryTrans.Where(trans =trans.T_PayeeId ==
qryPayeeId);
if (!string.IsNullOrEmpty(qryCatId))
qryTrans =
qryTrans.Where(trans =trans.T_Category == qryCatId);
}

// if Category selected, get transactions for the Category only
if (chkbxCategory.Checked)
{
if (!string.IsNullOrEmpty(qryCatId))
qryTrans =
qryTrans.Where(trans =trans.T_Category ==
qryCatId);
}

// if Payee selected, get transactions for the Payee only
if (chkbxPayee.Checked)
{
if (!string.IsNullOrEmpty(qryPayeeId))
qryTrans =
qryTrans.Where(trans =trans.T_PayeeId ==
qryPayeeId);
}

dgvSearchResults.DataSource = qryTrans.ToList();
}

Nov 11 '08 #1
8 2904
On Mon, 10 Nov 2008 20:15:00 -0800, Paolo
<Pa***@discussions.microsoft.comwrote:
Is there any way I can avoid the ugly and repetitive 'if' construct shown
below? [...]
Well, the most obvious improvement would be to remove your first if() test
(checking for a payee and category together), since the individual tests
will accomplish the same exact thing, and in fact do a redundant re-query
of the results.

Beyond that, I would just put all your conditions into the "where" clause
for your original query. For example:

where ((trans.T_Date >= qryStart) && (trans.T_Date <= qryEnd))
&& (!chkbxPayee.Checked || string.IsNullOrEmpty(qryPayeeId) ||
trans.T_PayeeId == qryPayeeId)
&& (!chkbxCategory.Checked || string.IsNullOrEmpty(qryCatId) ||
trans.T_Category == qryCatId)

If you're for some reason concerned about the minimal overhead of
examining the CheckBox and filter string states for each element in the
enumeration, you could factor those out of the query, using one of four
different lambda expressions in your where clause depending on the state
of those filters. But I think that that's probably more trouble than it's
worth.

Pete
Nov 11 '08 #2
Peter: thank you. Yes, I see now that the first 'if' is redundant and I will
remove it - that will 'unclutter' the code.

I'm not so sure about the big 'where' statement - I think doing that will
not aid readability.

Another question if I may. At the moment the results of the search are
displayed in a DataGridView (dgvSearchResults.DataSource =
qryTrans.ToList();) which is on the same Win form as the form which captures
the search criteria. My original thinking was to display the search result in
a DataGridView on a separate form.

What I'm not sure of is whether I can pass the results of the query to a
second form i.e. to make Form2.dgvSearchResults.DataSource =qryTrans.ToList();

Is this possible?

"Peter Duniho" wrote:
On Mon, 10 Nov 2008 20:15:00 -0800, Paolo
<Pa***@discussions.microsoft.comwrote:
Is there any way I can avoid the ugly and repetitive 'if' construct shown
below? [...]

Well, the most obvious improvement would be to remove your first if() test
(checking for a payee and category together), since the individual tests
will accomplish the same exact thing, and in fact do a redundant re-query
of the results.

Beyond that, I would just put all your conditions into the "where" clause
for your original query. For example:

where ((trans.T_Date >= qryStart) && (trans.T_Date <= qryEnd))
&& (!chkbxPayee.Checked || string.IsNullOrEmpty(qryPayeeId) ||
trans.T_PayeeId == qryPayeeId)
&& (!chkbxCategory.Checked || string.IsNullOrEmpty(qryCatId) ||
trans.T_Category == qryCatId)

If you're for some reason concerned about the minimal overhead of
examining the CheckBox and filter string states for each element in the
enumeration, you could factor those out of the query, using one of four
different lambda expressions in your where clause depending on the state
of those filters. But I think that that's probably more trouble than it's
worth.

Pete
Nov 11 '08 #3
On Mon, 10 Nov 2008 23:13:00 -0800, Paolo
<Pa***@discussions.microsoft.comwrote:
Peter: thank you. Yes, I see now that the first 'if' is redundant and I
will
remove it - that will 'unclutter' the code.

I'm not so sure about the big 'where' statement - I think doing that will
not aid readability.
I suppose that depends on how comfortable one is with boolean
expressions. I find it quite readable, much moreso than the procedural
if() statements.

That said, IMHO the biggest potential advantage isn't of readability, but
of performance. The code you posted enumerates through the current
results again for each additional filter. The change I suggest allows all
of the filtering to be done in a single enumeration of the original data.

For small data sets, this wouldn't matter, but for larger data sets it
could be significant.
Another question if I may. At the moment the results of the search are
displayed in a DataGridView (dgvSearchResults.DataSource =
qryTrans.ToList();) which is on the same Win form as the form which
captures
the search criteria. My original thinking was to display the search
result in
a DataGridView on a separate form.

What I'm not sure of is whether I can pass the results of the query to a
second form i.e. to make Form2.dgvSearchResults.DataSource
=qryTrans.ToList();

Is this possible?
I don't see why it wouldn't be, but without seeing the code you might use
to attempt that, it's impossible to say whether the specific approach you
have in mind would work. Generally speaking though, the query should not
have any specific ties to the original form, and so having some other form
use the results shouldn't be a problem.

Pete
Nov 11 '08 #4
Peter: I see what you are saying about extra/unnecessary iterations. My data
set is not going to be of 'industrial' proportions and, in that sense,
performance is not an issue. Nevertheless I do like to adhere to 'best
practice' or, at least, efficient coding practice so I will revisit that
'where' statement.

As far as using a second form is concerned I'd use something like this. I'm
struggling with how I can pass an anonymous type (qryTrans) as a parameter:

Form1 code:
private void searchbutton1_Click(object sender, EventArgs e)
{
Form2 frm2 = new Form2();
frm2.FormClosed += new FormClosedEventHandler(frm2_FormClosed);
frm2.Show();
this.Hide();

// pass query result to Form2
frm2.doSearch(transQry);
}

void frm2_FormClosed(object sender, FormClosedEventArgs e)
{
this.Show();
}

Form2 code:
public void doSearch(?????) // how express parameters for anonymous
type?
{
dgvSearchResults2.DataSource = qryTrans.ToList();
}

"Peter Duniho" wrote:
On Mon, 10 Nov 2008 23:13:00 -0800, Paolo
<Pa***@discussions.microsoft.comwrote:
Peter: thank you. Yes, I see now that the first 'if' is redundant and I
will
remove it - that will 'unclutter' the code.

I'm not so sure about the big 'where' statement - I think doing that will
not aid readability.

I suppose that depends on how comfortable one is with boolean
expressions. I find it quite readable, much moreso than the procedural
if() statements.

That said, IMHO the biggest potential advantage isn't of readability, but
of performance. The code you posted enumerates through the current
results again for each additional filter. The change I suggest allows all
of the filtering to be done in a single enumeration of the original data.

For small data sets, this wouldn't matter, but for larger data sets it
could be significant.
Another question if I may. At the moment the results of the search are
displayed in a DataGridView (dgvSearchResults.DataSource =
qryTrans.ToList();) which is on the same Win form as the form which
captures
the search criteria. My original thinking was to display the search
result in
a DataGridView on a separate form.

What I'm not sure of is whether I can pass the results of the query to a
second form i.e. to make Form2.dgvSearchResults.DataSource
=qryTrans.ToList();

Is this possible?

I don't see why it wouldn't be, but without seeing the code you might use
to attempt that, it's impossible to say whether the specific approach you
have in mind would work. Generally speaking though, the query should not
have any specific ties to the original form, and so having some other form
use the results shouldn't be a problem.

Pete
Nov 11 '08 #5
On Mon, 10 Nov 2008 23:48:01 -0800, Paolo
<Pa***@discussions.microsoft.comwrote:
[...]
As far as using a second form is concerned I'd use something like this.
I'm
struggling with how I can pass an anonymous type (qryTrans) as a
parameter:
You can't. The compiler only knows the anonymous type in the method where
it was declared.

Now, you should be able to return the query result as a non-generic
IEnumerable, and depending on how the other form is using it, that could
be enough. But if not, you should probably consider just not using an
anonymous type. It's simple enough to create an appropriate named type
that you can then reference in both classes. It would be possible to use
reflection, but that's an awful solution for something dealt with so
trivially through conventional techniques.

Pete
Nov 11 '08 #6
Pete: I thought as much. I suppose I could just transfer the query to the
second form and initiate it there when I 'show' that form.

As I'm still learning C#/LINQ, I'm not sure how I'd "return the query result
as a non-generic IEnumerable". Could you give me an example?

Thanks

"Peter Duniho" wrote:
On Mon, 10 Nov 2008 23:48:01 -0800, Paolo
<Pa***@discussions.microsoft.comwrote:
[...]
As far as using a second form is concerned I'd use something like this.
I'm
struggling with how I can pass an anonymous type (qryTrans) as a
parameter:

You can't. The compiler only knows the anonymous type in the method where
it was declared.

Now, you should be able to return the query result as a non-generic
IEnumerable, and depending on how the other form is using it, that could
be enough. But if not, you should probably consider just not using an
anonymous type. It's simple enough to create an appropriate named type
that you can then reference in both classes. It would be possible to use
reflection, but that's an awful solution for something dealt with so
trivially through conventional techniques.

Pete
Nov 11 '08 #7
On Tue, 11 Nov 2008 12:26:03 -0800, Paolo
<Pa***@discussions.microsoft.comwrote:
Pete: I thought as much. I suppose I could just transfer the query to the
second form and initiate it there when I 'show' that form.

As I'm still learning C#/LINQ, I'm not sure how I'd "return the query
result
as a non-generic IEnumerable". Could you give me an example?
Sure:

IEnumerable Method()
{
var result = ...; // some LINQ query

return result;
}

The whole point of LINQ queries is that they generate types that are
enumerable. As such, they implement IEnumerable as well as whatever
strongly-typed IEnumerable<Tis appropriate for the query (all
IEnumerable<Timplementors have to implement IEnumerable as well).

As I mentioned, this may or may not actually suit your needs. You still
won't have type information for the objects in the collection, and so
without reflection there's not much you can do with it. You can call
ToString(), and if the default output from ToString() for anonymous types
is okay for your purposes, you can even use that directly. Ironically, it
might be faster to call ToString() and parse the output instead of using
reflection...again, depending on what you're actually doing.

In other words, you'll be very limited in what you can do. But you can in
fact do it that way if you decide that works for you. Given that the
DataSource property isn't going to be able to use the compile-time typing
of your anonymous type anyway (i.e. internally it's going to have to use
reflection anyway), I suspect that this would work just fine. To get an
IList to assign to your DataSource, you'll probably have to do something
like this:

IEnumerable result = Method(); // a method that returns IEnumerable,
e.g. as above

dgv.DataSource = result.Cast<object>().ToList();

You can't call ToList<T>() on the non-generic IEnumerable, but you can
easily use the Cast<T>() extension method to convert to an
IEnumerable<objecton which you _can_ call ToList<T>().

Note that, depending on the design of your program, you might find it's
appropriate to pass a reference of your second form, or the DataGridView
instance itself, to the method that is actually generating the anonymous
type. That's a completely different approach that might work fine,
depending on what you're really trying to do here.

Pete
Nov 11 '08 #8
Pete: many thanks - that's brilliant. I'll need to cogitate on it a bit (as I
said, I'm still learning!) but I think, together with the various books I'm
using to learn C#/LINQ, I'll be able to develop a workable solution based on
your example.

Paul

"Peter Duniho" wrote:
On Tue, 11 Nov 2008 12:26:03 -0800, Paolo
<Pa***@discussions.microsoft.comwrote:
Pete: I thought as much. I suppose I could just transfer the query to the
second form and initiate it there when I 'show' that form.

As I'm still learning C#/LINQ, I'm not sure how I'd "return the query
result
as a non-generic IEnumerable". Could you give me an example?

Sure:

IEnumerable Method()
{
var result = ...; // some LINQ query

return result;
}

The whole point of LINQ queries is that they generate types that are
enumerable. As such, they implement IEnumerable as well as whatever
strongly-typed IEnumerable<Tis appropriate for the query (all
IEnumerable<Timplementors have to implement IEnumerable as well).

As I mentioned, this may or may not actually suit your needs. You still
won't have type information for the objects in the collection, and so
without reflection there's not much you can do with it. You can call
ToString(), and if the default output from ToString() for anonymous types
is okay for your purposes, you can even use that directly. Ironically, it
might be faster to call ToString() and parse the output instead of using
reflection...again, depending on what you're actually doing.

In other words, you'll be very limited in what you can do. But you can in
fact do it that way if you decide that works for you. Given that the
DataSource property isn't going to be able to use the compile-time typing
of your anonymous type anyway (i.e. internally it's going to have to use
reflection anyway), I suspect that this would work just fine. To get an
IList to assign to your DataSource, you'll probably have to do something
like this:

IEnumerable result = Method(); // a method that returns IEnumerable,
e.g. as above

dgv.DataSource = result.Cast<object>().ToList();

You can't call ToList<T>() on the non-generic IEnumerable, but you can
easily use the Cast<T>() extension method to convert to an
IEnumerable<objecton which you _can_ call ToList<T>().

Note that, depending on the design of your program, you might find it's
appropriate to pass a reference of your second form, or the DataGridView
instance itself, to the method that is actually generating the anonymous
type. That's a completely different approach that might work fine,
depending on what you're really trying to do here.

Pete
Nov 11 '08 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Ed Severn | last post by:
I'm sorry of this question has been posed and answered many times before. But I have avoided using the "package" statement because of this. Most of my classes have no "package" statement, and...
0
by: Carlos Ribeiro | last post by:
I thought about this problem over the weekend, after long hours of hacking some metaclasses to allow me to express some real case data structures as Python classes. I think that this is something...
76
by: Nick Coghlan | last post by:
GvR has commented that he want to get rid of the lambda keyword for Python 3.0. Getting rid of lambda seems like a worthy goal, but I'd prefer to see it dropped in favour of a different syntax,...
3
by: H. S. | last post by:
Hi, I am trying to compile these set of C++ files and trying out class inheritence and function pointers. Can anybody shed some light why my compiler is not compiling them and where I am going...
1
by: Paul E Collins | last post by:
This does what you'd expect ... string foo = { "bar", "baz", "quux" }; .... so why is this a syntax error? private string foo() { return { "bar", "baz", "quux" }; }
0
by: Cordell Lawrence | last post by:
Okay guys, We are wondering if this is a bug in Framework 2.0.40607 and looking for some clarification on the issue. Take a look at the folowing code. public delegate bool BoundryTest(int...
4
by: Harold Howe | last post by:
I am running into a situation where the compiler complains that it cannot infer the type parameters of a generic method when one of the function arguments is an anonymous method. Here is a...
60
by: jacob navia | last post by:
Gnu C features some interesting extensions, among others compound statements that return a value. For instance: ({ int y = foo(); int z; if (y>0) z = y; else z=-y; z; }) A block enclosed by...
2
by: sybot_uk | last post by:
Hi there, I am writing a query in DB2 which needs to return a result set, i want to be able to use a couple of variables in query to speed things up. Please can anyone tell me how i may do this?...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.