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();
Related
I'm trying to filter the response from the below controller. I dont want the variables to be included in the search if they are empty
public async Task<IEnumerable<Models.Clients>> GetAllClients(string client_type = "",
string company_type = "", string sales_agent = "", string country = "")
{
var result = await GetClients();
if (client_type.Length > 0 || company_type.Length > 0 || sales_agent.Length > 0 ||
country.Length > 0)
{
// Here I want to exclude the variables from the search if they are = ""
var s = result
.Where(item => client_type?.ToString() == item.client_type?.ToString() &&
company_type?.ToString() == item.company_type?.ToString());
return s;
}
else
{
return result;
}
}
The question is basically how I can exclude the variables from the search if they are empty.
You can construct the query by applying the Where-clause several times.
IEnumerable<Models.Clients> result = await GetClients();
if(client_type.Length > 0) {
result = result.Where(c => c.client_type.ToString() == client_type);
}
if(company_type.Length > 0) {
result = result.Where(c => c.company_type.ToString() == company_type);
}
if(sales_agent.Length > 0) {
result = result.Where(c => c.sales_agent.ToString() == sales_agent);
}
if(country.Length > 0) {
result = result.Where(c => c.country.ToString() == country);
}
return result;
If you apply this approach when querying a database through an O/R-mapper (e.g. EF or EF Core), then the Where-clauses will be translated to comparisons joined by AND in SQL. If you are querying objects, you can also combine the parts with && instead as in:
pattern1.Length == 0 || c.prop1 == pattern1 &&
pattern2.Length == 0 || c.prop2 == pattern2 &&
...
Also, I am not sure what the type of the properties in the Models.Clients is. If they are strings, then you can drop the .ToString() calls. You can drop it anyway for the string parameters, as they are strings already.
If the types are not strings, the question is, why you are not using the same types or a nullable version of them as parameters? If this is a user input from a TextBox, this is okay, but otherwise, consider using the same type and drop all of the .ToString() calls.
If you are sticking to string: Are you sure that the stringa are never null? If they can be null, rather use !String.IsNullOrEmpty(theString) as #Kit suggests.
I want to verify that a string does not contain any duplicate characters (from a set of bad characters) in adjacent positions. Previous stack overflow answers on this subject seem to mostly be of the general form:
for(int i = 0; i < testString.Length-1; i++){
if(testString[i] == testString[i+1] && testString[i] == badChar){
//Handle rejection here
}
}
Is it possible to do this kind of verification/validation in LINQ? More generically: is it possible within LINQ to compare the value of each character in a string to the next character in a
testString.Any(c => /*test goes here*/) call?
Anytime you have a class that has Count (or equivalent) property and indexer, you can use Enumerable.Range as base for the LINQ query and perform inside an indexed access similar to the non LINQ code:
bool test = Enumerable.Range(0, testString.Length - 1).Any(i = >
testString[i] == testString[i + 1] && testString[i] == badChar)
You could use Pairwise from moreLINQ library:
if(testString.Pairwise((n, m) => new {n, m}).Any(x => x.n == x.m && x.n == badChar))
// do something
If you want to use pure LINQ you could hack it with Skip/Zip combination:
if(testString.Zip(testString.Skip(1), (n, m) => new {n, m})).Any(x => x.n == x.m && x.n == badChar))
// do something
But both these solutions will be much slower then for loop-based solution, so I'd advice against doing that.
How about the egregious misuse of the aggregate function? I like to think this answer is more of an example of what not to do, even if it is possible. A while and string.indexOf are probably the most appropriate to this problem.
var items = "ab^cdeef##gg";
var badChars = new[] {'^', '#', '~'};
var doesAdjacentDupeExist = false;
var meaninglessAggregate = items.Aggregate((last, current) =>
{
if (last == current && badChars.Contains(last))
{
doesAdjacentDupeExist = true;
};
return current;
});
This is not as clever, but it does work. It trades the setting of an outside variable inside the query (bad), for relying on index and elementAt (not great).
var items = "abcdefffghhijjk";
var badChars = new[] { 'f', 'h' };
var indexCieling = items.Count() - 1;
var badCharIndexes = items.Select((item, index) =>
{
if (index >= indexCieling)
{
return null as int?;
}
else
{
if (item == items.ElementAt(index + 1) && badChars.Contains(item))
{
return index as int?;
}
else
{
return null as int?;
}
}
});
var doesAdjacentDupeExist = badCharIndexes.Any(x => x.HasValue);
Alright, so I need to get the key value paired differences of two data rows. In short, I'm sending an email to let a user know they've made specific changes to their profile. I already know the rows are different because I'm using the SequenceEqual to determine that.
At the moment I've written and debugged the following code:
if (currentRow.ItemArray.SequenceEqual(updatedRow)) { return; }
var updates = currentRow.ItemArray
.Where((o, i) =>
{
if (o == null && updatedRow[i] == null) { return false; }
else if (o == null && updatedRow[i] != null) { return true; }
else if (o.Equals(updatedRow[i])) { return false; }
return true;
})
.Select((o, i) =>
{
return new AppServices.NotificationData
{
Key = updatedRow.Table.Columns[i].ColumnName,
Value = Convert.ToString(updatedRow[i])
};
}).ToList();
But there are two problems with this code:
It seems really inefficient to me because it's going through each value in the ItemArray and then building a key value pair if the values differ.
It doesn't actually work because the i sent into the Select isn't correct (e.g. if the second column changed, 1, the index sent into the Select is actually 0. Honestly, that makes sense, but I'm not sure exactly how to get what I want here.
CONSTRAINT: I'd like to use LINQ here.
NOTE: I'm only comparing two rows (i.e. it's not going to be going through a list of rows).
What is the appropriate LINQ statement for what I'm trying to do here?
UPDATE: It really feels like I just need to use:
currentRow.ItemArray.Intersect(updatedRow.ItemArray)
but the problem with that is I don't have any idea what field that is so I can't build a key value pair. In other words, I get back only the differences, but I've no clue what the index is so I can't go get a column name based off of those values.
Honestly you're not going to lose much code clarity by using a for loop.
public IEnumerable<AppServices.NotificationData> GetUpdates(DataRow currentRow, DataRow updatedRow)
{
if (currentRow.ItemArray.SequenceEqual(updatedRow)) yield break;
var length = currentRow.ItemArray.Length;
for(var i = 0; i < length; i++)
{
var currentCol = currentRow[i];
var updatedCol = updatedRow[i];
if (currentCol == null && updatedCol == null) continue;
else if (currentCol == null && updatedCol != null) continue;
else if (currentCol.Equals(updatedCol)) continue;
yield return new AppServices.NotificationData
{
Key = updatedRow.Table.Columns[i].ColumnName,
Value = Convert.ToString(updatedCol)
};
}
}
var updates = currentRow.ItemArray
.Select((o, i) => new { Row = o, Index = i })
.Where(r => (r.Row == null && updatedRow[r.Index] != null)
|| (r.Row != null && updatedRow[r.Index] != null
&& !r.Row.Equals(updatedRow[r.Index])))
.Select(r => new
{
Key = updatedRow.Table.Columns[r.Index].ColumnName,
Value = Convert.ToString(updatedRow[r.Index])
}).ToList();
In general, I consider using array index values in LINQ to be a "code smell", and this is a good example of why: the Where clause, in generating a new sequence of values, destroys the illusion that the Select clause is working on the same collection as before.
A quick hack to get around this right now (though I don't think it is quite yet the right solution), would be to swap your Where and Select clauses, essentially:
if (currentRow.ItemArray.SequenceEqual(updatedRow)) { return; }
var updates = currentRow.ItemArray
.Select((o, i) =>
{
if (o == null && updatedRow[i] == null || o.Equals(updatedRow[i])) { return null; }
else return new AppServices.NotificationData
{
Key = updatedRow.Table.Columns[i].ColumnName,
Value = Convert.ToString(updatedRow[i])
};
}).Where(o => o != null).ToList();
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.
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.