c# if else then statement with LINQ - c#

I have the following code:
if (intval == 0)
{
var result = (from dm in datacontext.Trk
where dm.ID == 0
select dm);
}
else
{
var result = (from dm in datacontext.Trk
where dm.ID != 0
select dm);
}
if (result != null)
{
// do something
}
There is a swigly line under the result in if (result!= null) saying that the name result does not exist in the current context.
Not sure how to fix this. I tried to initially var result = null but C# didn't like that.

The variable is limited to the block it is declared in. So you have two results, one in if block and one in else block which are different and are not visible outside their blocks.
You need to define the variable out of blocks, but then you need to be specific about the type, because C# compiler needs direct assignment expression to infer the type for var keyword.
However, I suggest rethinking your code and doing somthing like following:
var result = from dm in datacontext.Trk
where ((intval == 0) ? dm.ID == 0 : dm.ID != 0)
select dm;
if (result.Any())
{
// do something
}
Please also note that result will never be null, therefore, I have replaced it with Any but it is not a gist of the question, I believe.

how about something like this:
var result =
intval == 0
?(from dm in datacontext.Trk where dm.ID = 0 select dm)
:(from dm in datacontext.Trk where dm.ID != 0 select dm);
if(results.Any())
{
...
}

You need to declare result before the if statement:
object result = null;
if (intval = 0)
{
result = (from dm in datacontext.Trk
where dm.ID = 0
select dm);
}
else
{
result = (from dm in datacontext.Trk
where dm.ID != 0
select dm);
}
if (result != null)
{
// do something
}
Or you can keep the var declaration in this other variant:
var result = (from dm in datacontext.Trk
where dm.ID != 0
select dm);
if (intval = 0)
{
result = (from dm in datacontext.Trk
where dm.ID = 0
select dm);
}
if (result != null)
{
// do something
}
Now you should somehow find a way to either change that if or remove it completely because result cannot be null at that point.

You can perform the where separately from the main query:
var result = from dm in datacontext.Trk select dm;
if (intval == 0)
{
result = result.Where(dm => dm.ID == 0);
}
else
{
result = result.Where(dm => dm.ID != 0);
}
if (result.Any())
{
// do something
}

You need to declare the result variable before the first if-else.
Also you need paranthesis around the condition in the second if statement.

This code would also cause the problem:
if (value == 0)
{
int result = 1;
}
else
{
string result = "testing";
}
if (result != 1)
{
// do something
}
The first time result is an int, the second time I declare a string, and the third time result is undeclared. The reason that they can have different types is because the first two declarations belong to different scopes. Each { ... } gets its own scope.
If you want to share one variable between scopes, you'll need to declare it outside. But now, since the same variable is used in all three places, there is a compiler error that the types don't match:
int result;
if (value == 0)
{
result = 1;
}
else
{
result = "testing"; // type error here
}
if (result != 1)
{
// do something
}

List<TypeOfDm> dmList; // <=== Declare dmList outside of block statements.
if (intval == 0) { // <=== Use "==" for comparision, "=" is assignement.
dmList = datacontext.Trk
.Where(dm => dm.ID == 0)
.ToList();
} else {
dmList = datacontext.Trk
.Where(dm => dm.ID != 0)
.ToList();
}
if (dmList.Count != 0) {
// do something
}
Note, with your code your result will always be non-null.

Related

How to avoid using IF-Else and use inline if condition inside the .where() function?

q = q.Where(s =>
!matchingRecords.Contains(s.Id)
|| (s.SecId != null)
);
but the matchingrecords could be null or having 0 items in it since it's a list. So, in that case it would fail in the above code. I want to check this contains only if
the matching records is not null and have some elements else not.
One way is to put IF-Else block and repeat the code but I want to do it inline, how ?
So, if input conditions are:
matchingRecords is not null;
matchingRecords not empty (contains elements, .Count > 0);
no if-else usage allowed;
could it be done through ternary?
var list = matchingRecords?.Count > 0 ?
q.Where(s => !matchingRecords.Contains(s.Id) && s.SecId != null).ToList()
: new List<Record>();
matchingRecords? checks for null and .Count after checks for "not empty". If-else replaced with ternary, which would filter collection using Where or return new List<Record> on else case.
Sample:
class Program
{
private static List<int> matchingRecords; // It is null, we "forget" to initialize it
static void Main(string[] args)
{
var list = new List<Record>()
{
new Record { Id = 0, SecId ="Some SeqId" },
new Record { Id = 1, SecId = null },
new Record { Id = 2, SecId = "Another SeqId" },
};
var filteredRecords = FilterRecords(list);
}
static IEnumerable<Record> FilterRecords(IEnumerable<Record> q)
{
return matchingRecords?.Count > 0 ? // Checking for not null and not empty (if case)
q.Where(s => !matchingRecords.Contains(s.Id) && s.SecId != null)
: q; // else case
}
}
public class Record
{
public int Id { get; set; }
public string SecId { get; set; }
}
Not sure that properly reproduced your situation, so correct me if something is wrong.
q = q.Where(s => (matchingRecords != null && matchingRecords.Count > 0 &&
!matchingRecords.Contains(s.Id))
|| (s.SecId != null)
);
The condition matchingRecords != null && matchingRecords.Count > 0 will ensure !matchingRecords.Contains(s.Id) is executed only if matchingRecords has at least 1 record

Index was outside the bounds C#

i got error as: An unhandled exception of type 'System.IndexOutOfRangeException' occurred in app.exe
Additional information: Index was outside the bounds of the array.
by using code below, i appreciate your help in-advance all.
public string getMissingFields(WebBrowser wb, DataRow dr)
{
string Available2 = "";
Available2 = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt")
.Style.Split(';')
.Where(x => x.Contains("display"))
.ToArray()[0].Split(':')[1];
string FieldsMissing="";
if( Available2 .Contains( "inline" )) {
FieldsMissing = FieldsMissing + "First name missing!" + ", ";
}
return FieldsMissing;
}
You're assumiing that the style will always contain "display", which apparently it does not. Replace your indexer call to offset 0 with a call to FirstOrDefault(), then test for null:
Available2 = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt").Style.Split(';').Where(x => x.Contains("display")).ToArray().FirstOrDefault();
if( null != Available2 )
{
// continue
}
Available2 = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt")
.Style.Split(';')
.Where(x => x.Contains("display"))
.ToArray()[0].Split(':')[1];
Two possible problems:
Either ToArray() does return an empty array, at with point accessing element 0 causes this error. Or it is at the point where you are accessing the element at index 1 - maybe there is no such element, because in the string you're trying to split there is no :? Debug your code or make sure that there is at least one element returned by ToArray() and two elements returned by Split.
You could try this now. This splits your code so that you can easily debug:
var items = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt")
.Style.Split(';')
.Where(x => x.Contains("display"))
.ToArray();
if (items.Count > 0)
{
string[] split = items[0].Split(':');
if (split.Length > 1)
Available2 = split[1];
}
Two possibilities:
ToArray() returning empty array.You are trying to an element which is not exist.
Split(':') returning zero or one element.
Debug your code and find which one is true.
It seems you don't need ToArray.Just use FirstOrDefault, and check returning result whether null or not.If it isn't null call Split and check again to prevent exception.
Available2 = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt")
.Style.Split(';')
.Where(x => x.Contains("display"))
.FirstOrDefault();
if(Available2 != null)
{
var text = Available2.Split(':');
if(text.Length > 1)
{
var result = text[1];
}
}
First, consider that there's no control with id=ContentPlaceHolder1_reqTxt:
var reqTxt = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt");
You have to handle the case that it's null:
if(reqTxt != null)
{
}
Now consider that there's is no style display, then ToArray returns an empty array. You can use FirstOrDefault and check for null gain:
string Available2 = null;
if(reqTxt != null)
{
var firstDisplayStyle = reqTxt.Split(';')
.FirstOrDefault(s => s.Contains("display"));
if(firstDisplayStyle != null)
{
string[] displaySplit = firstDisplayStyle.Split(':');
// now handle the case that there is no colon:
if(displaySplit.Length > 1)
Available2 = displaySplit[1];
}
}
Available2=wb.Document.GetElementById("ContentPlaceHolder1_reqTxt").Style.Split(';').Where(x => x.Contains("display")).ToArray()[0].Split(':')[1];
To find problem, decomposite to:
if (wb == null || wb.Document == null )
return;
var element = wb.Document.GetElementById("ContentPlaceHolder1_reqTxt");
if (element == null || element.Style == null)
return;
var displayItems = element.style.Split(';').Where(x=> x.Contains("display")).FirstOrDefault();
if ( displayItems == null)
return;
var colonItems = displayItems.Split(':');
if ( colonItems.Count() < 2 )
return;
var Available2 = colonItems.Skip(1).First();

LINQ where condition filtering

String Sex = getSex(); // return M or F
String[] members = getMembers(); // return member codes in array or null
//if members array is null, no filtering for member codes
var query = from tb in MemberTable
where tb.sex.Equals(Sex) &&
(members != null ? members.Contains(tb.membercode) : true)
select tb;
The code doesn't return correct result. It returns all members no matter what members[] is.
Actually the original LINQ is complex so if there are any other possible solutions, I do not want to write the following:
if (members == null){ /*LINQ1*/ }
else { /*LINQ2*/ }
which is not a good coding style.
Any suggestion for solving this problem?
var query = MemberTable.Where(x=>x.sex.Equals(Sex))
if (members != null)
query = query.Where(x=>members.Contains(x.membercode))
//use your query
query.ToList();
OR
var query = from tb in MemberTable
where tb.sex.Equals(Sex) &&
(members == null || members.Contains(tb.membercode))
select tb;
I prefer the first.
Since || short-circuits, you should be able to do this:
var query = from tb in MemberTable
where tb.sex.Equals(Sex) &&
(members == null || members.Contains(tb.membercode))
select tb;
The (members == null || members.Contains(tb.membercode)) subexpression will be true if members is null, so Contains would not be evaluated.
var list = new List<ModelName>();
list = ctx.MemberTable
.Where(c => c.sex==Sex)
.Where(c => c.membercode==true)
.ToList();

Declaring anonymous type as array correctly to keep scope

All I want to do is declare var place correctly so it is still in scope once I get to the foreach loop. I'm assuming I need to declare it before the if statement for connections. Is this a correct assumption and if so how do I declare it? Thanks!
using (var db = new DataClasses1DataContext())
{
if (connections == "Connections")
{
var place = (from v in db.pdx_aparts
where v.Latitude != null && v.Region == region && v.WD_Connect >= 1
select new
{
locName = v.Apartment_complex.Trim().Replace(#"""", ""),
latitude = v.Latitude,
longitude = v.Longitude
}).Distinct().ToArray();
}
else
{
var place = (from v in db.pdx_aparts
where v.Latitude != null && v.Region == region && ((v.WD_Connect == null) || (v.WD_Connect == 0))
select new
{
locName = v.Apartment_complex.Trim().Replace(#"""", ""),
latitude = v.Latitude,
longitude = v.Longitude
}).Distinct().ToArray();
}
foreach (var result in place)
....
You can create an array with a single entry whose value you ignore later:
// Note: names *and types* must match the ones you use later on.
var place = new[] { new { locName = "", latitude = 0.0, longitude = 0.0 } };
if (connections = "Connections")
{
// Note: not a variable declaration
place = ...;
}
else
{
place = ...;
}
This works because every use of anonymous types using properties with the same names and types, in the same order, will use the same concrete type.
I think it would be better to make the code only differ in the parts that it needs to though:
var query = v.db.pdx_aparts.Where(v => v.Latitude != null && v.Region == region);
query = connections == "Connections"
? query.Where(v => v.WD_Connect >= 1)
: query.Where(v => v.WD_Connect == null || v.WD_Connect == 0);
var places = query.Select(v => new
{
locName = v.Apartment_complex
.Trim()
.Replace("\"", ""),
latitude = v.Latitude,
longitude = v.Longitude
})
.Distinct()
.ToArray();
Here it's much easier to tell that the only part which depends on the connections value is the section of the query which deals with WD_Connect.
You could convert the if to a ?:.
var place = connections == "Connections" ? monsterQuery1 : monsterQuery2;
I do not think this is a good solution because your queries are too big (unreadable).
It would be much better if you introduced a named class that you use instead of the anonymous type. R# does that for you in a "light bulb menu" refactoring.
you could just use the 1 query since they are pretty much the same, and just add the extra condition in the where clause
var place = (from v in db.pdx_aparts
where v.Latitude != null && v.Region == region
&& connections == "Connections"
? v.WD_Connect >= 1
: ((v.WD_Connect == null) || (v.WD_Connect == 0))
select new
{
locName = v.Apartment_complex.Trim().Replace(#"""", ""),
latitude = v.Latitude,
longitude = v.Longitude
}).Distinct().ToArray();
foreach (var result in place)
....

InvalidCastException error with linq

Below my code. It returns exception "InvalidCastException". And main question is - why?What is wrong?
Error text:
Unable to cast object of type
'WhereSelectListIterator`2[Monopolowy_beta.Gracz,Monopolowy_beta.Gracz]'
to type 'Monopolowy_beta.Gracz'.
namespace Monopolowy_beta
{
class Program
{
static void Main(string[] args)
{
List<Gracz> lista = new List<Gracz> { };
Gracz g1 = new Gracz();
Gracz g2 = new Gracz();
Gracz g3 = new Gracz();
g2.Id = 3;
lista.Add(g1);
lista.Add(g2);
lista.Add(g3);
g1 = GraczeTools.UstawAktywnegoGracza(lista, 3);
Console.ReadKey();
}
}
}
Error in these lines:
var docelowy = from item in listagraczy where (item.Id==ID && item.czyAktywny == true) select listagraczy[listagraczy.IndexOf(item) + 1];
gracz = (Gracz)docelowy;
namespace Monopolowy_beta
{
static class GraczeTools
{
public static Gracz UstawAktywnegoGracza(List<Gracz> listagraczy, int ID)
{
Gracz gracz = new Gracz();
if (ID == 4){
var docelowy = from item in listagraczy where (item.czyAktywny == true && item.Id == 3) select listagraczy[1];
gracz = (Gracz)docelowy;
}
if (ID != 4){
var docelowy = from item in listagraczy where (item.Id==ID && item.czyAktywny == true) select listagraczy[listagraczy.IndexOf(item) + 1];
gracz = (Gracz)docelowy;
}
return gracz;
}
}
}
var docelowy = from item in listagraczy
where (item.czyAktywny == true && item.Id == 3)
select listagraczy[1];
Let's examine this query. It finds all items which satisfy condition (yes, it will return sequence, not single item) and for each such item, it returns.. second element of listagraczy list. Yes, you don't have items, which matched your condition.
I think you should select item instead (this a range variable of your query), and apply FirstOrDefault to result, because by default query will return IEnumerable<Gracz> result.
var docelowy = (from item in listagraczy
where (item.czyAktywny == true && item.Id == 3)
select item).FirstOrDefault();
Which is better to write with fluent API:
var docelowy = listagraczy.FirstOrDefault(item => item.czyAktywny && item.Id == 3);
Also you can use boolean values directly in conditions (i.e. item.czyAktywny instead of item.czyAktywny == true).
After little refactoring your method should look like
public static Gracz UstawAktywnegoGracza(List<Gracz> listagraczy, int ID)
{
return listagraczy
.FirstOrDefault(item => item.Id == 3 && (ID != 4 || item.czyAktywny));
}
How it works:
You have two conditional blocks in your method if (ID == 4) and if (ID != 4) (which is actually if ... else. Difference is that you are filtering sequence by one more condition in first case - item.czyAktywny should be true. In second case this property does not matter. So, you can add one filtering condition instead (ID != 4 || item.czyAktywny) - czyAktywny will be verified only if ID equal to 4. Also you don't need to create new Gracz object in your method, because you anyway return one from passed list.
Instead of gracz = (Gracz)docelowy;, use gracz = docelowy.FirstOrDefault();
Your select statement is returning an IEnumerable<Gracz>. So, when you attempt to cast it to Gracz directly, the computer doesn't know how to do that and throws the error you're seeing.
There are a number of ways you can handle this situation, but the simplest would be to simply add FirstOrDefault to your invocation, giving you
gracz = docelowy.FirstOrDefault();
instead of what you currently have. By the way, you'll need to add this to your other if statement too - it has the same problem.

Categories

Resources