So I have a fitler TextBox where I want to search for different type of docs in a grid the code where I have different type of columns such as: Date,DocId,ClientId.
For a search I write on a filter Textbox something like that DocId:2002 and It just work fine but when I try to make a multiple search for example DocId:2002 ClientId:201 It doesnt search because of the return it just does an infinite loop.
private void TextBoxFilter_TextChanged(object sender, TextChangedEventArgs e)
{
foreach (Match m in Regex.Matches((sender as TextBox).Text, pattern, options))
{
if (m.Value != "")
{
Func<String, String> untilSlash = (s) => { return filters[re.Match(s).Groups[1].ToString()] = re.Match(s).Groups[2].ToString(); };
untilSlash(m.Value);
}
}
ICollectionView cv = CollectionViewSource.GetDefaultView(this.DataGridDocList.ItemsSource);
if (filters.Count == 0)
{
cv.Filter = null;
}
else
{
cv.Filter = o =>
{
for (int i = 0; i < filters.Count; i++)
{
if (filters.ElementAt(i).Key == "Date")
{
if (DateVerify.Match(filters.ElementAt(i).Value).Success)
{
return (o as Document).DateCreated < Convert.ToDateTime(DateVerify.Match(filters.ElementAt(i).Value).Groups[1].ToString()) && (o as Document).DateCreated > Convert.ToDateTime(DateVerify.Match(filters.ElementAt(i).Value).Groups[2].ToString());
}
else
{
var dateString = (o as Document).DateCreated.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
return dateString.Contains(DateVerify.Match(filters.ElementAt(i).Value).Groups[1].ToString());
}
}
if (filters.ElementAt(i).Key == "DocId")
{
return (o as Document).DocumentId.ToString().Contains(filters.ElementAt(i).Value);
}
if (filters.ElementAt(i).Key == "ClientId")
{
return (o as Document).ClientId.ToUpper().Contains(filters.ElementAt(i).Value.ToUpper());
}
}
return false;
};
filters.Clear();
}
}
So my question is how can I do an big search with all the filters at one time?
Manually I can add them 1 by 1 and it will be something like search1 && search2 && search3 but It will take too much time and It's probably not the best solution
There are many ways of building up the predicate. However my suggestion is to keep it simple and just create one method that returns true or false. It's good practice to only return once in a method.
The code below if for illustration purposes (as I'm unable to test it):
ICollectionView cv = CollectionViewSource.GetDefaultView(this.DataGridDocList.ItemsSource);
if (filters.Any())
{
cv.Filter = new Predicate<object>(PredicateFilter);
}
else
{
cv.Filter = null;
}
Then Predicate method to filter results:
public bool PredicateFilter(object docObj)
{
Document doc = docObj as Document;
var response = new List<bool>();
for (int i = 0; i < filters.Count; i++)
{
if (filters.ElementAt(i).Key == "Date")
{
if (DateVerify.Match(filters.ElementAt(i).Value).Success)
{
response.Add(doc.DateCreated < Convert.ToDateTime(DateVerify.Match(filters.ElementAt(i).Value).Groups[1].ToString()) && doc.DateCreated > Convert.ToDateTime(DateVerify.Match(filters.ElementAt(i).Value).Groups[2].ToString()));
}
else
{
var dateString = doc.DateCreated.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
response.Add(dateString.Contains(DateVerify.Match(filters.ElementAt(i).Value).Groups[1].ToString()));
}
}
else if (filters.ElementAt(i).Key == "DocId")
{
response.Add(doc.DocumentId.ToString().Contains(filters.ElementAt(i).Value));
}
else if (filters.ElementAt(i).Key == "ClientId")
{
response.Add(doc.ClientId.ToUpper().Contains(filters.ElementAt(i).Value.ToUpper()));
}
}
return response.All(m => m); // if all filters came back with true, return 1 response of true else false.
}
I have C# code; when run to a line, it throws a System.NullReferenceException.
Here is the line of the code that cause the exception
if (expDic != null && expression != null)
{
expDic.Add(i, expression.ToString())
}
Here is the stack trace in the code
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
at Sustainability.BusinessObject.CalculationManager.<>c__DisplayClass18_0.<HandleFormulaInner>b__0(Object args) in D:\HK\Desktop\VSTS_2\Sustainability.BusinessObject\Classes\CalculationManager.cs:line 1410
at System.Threading.Tasks.Task.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
I found that both expDic and expression are not null, however it throws a null reference exception.
Here is my code:
int count = table.Rows.Count;
Dictionary<int, string> expDic = new Dictionary<int, string>();
List<Task> taskList = new List<Task>();
for (int f = 0; f < count; f++)
{
DataRow tempformula = table.Rows[f];
string formulaSymbol = Convert.ToString(tempformula[Common.Systems.Sustainability.Constants.IndicatorFormula.Symbol]);
var t = Task.Factory.StartNew(new Action<object>((args) => {
int i = (int)args;
_sem.Wait();
StringBuilder expression = new StringBuilder(1024);
using (DataTable dt = new DataTable())
{
// symbol in the last line of formula
if (exp.EndsWith("+")
|| exp.EndsWith("-")
|| exp.EndsWith("*")
|| exp.EndsWith("/"))
{
exp = exp.Substring(0, exp.Length - 1);
}
object result = dt.Compute(exp, "");
expression.Append(result);
}
}
{
if (!string.IsNullOrWhiteSpace(symbol)
&& expression.Length > 0)
{
if (i + 1 >= count && symbol != ")")
{
}
else if (expression.ToString() != symbol)
{
expression.Append(symbol);
}
}
else if (expression.Length == 0 && symbol == "(")
{
expression.Append(symbol);
}
if (symbol == "days")
{
// calculating average values by days.
if (fromDate != null && toDate != null)
{
int days = toDate.Value.Subtract(fromDate.Value).Days + 1;
expression.Append(days);
}
else
{
expression.Append(1);
}
}
}
//Here is the code will have problem
if (expDic != null && expression != null)
{
expDic.Add(i, expression.ToString());
}
_sem.Release();
}), f);
taskList.Add(t);
}
I am doubting it is caused by the StartNew multithreading pattern,
so what is wrong in my code and how can I fix it?
I have Task.Factory.StartNew in C# code with args argument. I am not quite understand what value will arg be. So what value will args be and how the value is determined?
int count = table.Rows.Count;
Dictionary<int, string> expDic = new Dictionary<int, string>();
List<Task> taskList = new List<Task>();
for (int f = 0; f < count; f++)
{
DataRow tempformula = table.Rows[f];
string formulaSymbol = Convert.ToString(tempformula[Common.Systems.Sustainability.Constants.IndicatorFormula.Symbol]);
var t = Task.Factory.StartNew(new Action<object>((args) => {
int i = (int)args;
_sem.Wait();
StringBuilder expression = new StringBuilder(1024);
DataRow formula = table.Rows[i];
int indID = Convert.ToInt32(formula[Common.Systems.Sustainability.Constants.IndicatorFormula.IndicatorID]);
int sequence = Convert.ToInt32(formula[Common.Systems.Sustainability.Constants.IndicatorFormula.Sequence]);
int? referenceIndID = Common.Util.TryToConvertToInt32(formula, Common.Systems.Sustainability.Constants.IndicatorFormula.ReferenceIndicatorID);
decimal? val = Common.Util.TryToConvertToDecimal(formula, Common.Systems.Sustainability.Constants.IndicatorFormula.Value);
string symbol = Convert.ToString(formula[Common.Systems.Sustainability.Constants.IndicatorFormula.Symbol]);
string formulaOutputUnit = Convert.ToString(formula[Common.Systems.Sustainability.Constants.Indicator.Unit]);
if (!string.IsNullOrWhiteSpace(callerAcceptedUnit)) // added by HC on 2016-05-27
{
formulaOutputUnit = callerAcceptedUnit;
}
if (referenceIndID == null)
{
if (val == null)
{
DataSet indicator = GetIndicatorByIDFromCache(companyID, indID); // added by HC on 2017-05-12, for performance tuning.
//using (DataSet indicator = indicatorMgr.GetIndicatorByID(companyID, indID))
{
DataRow dr = indicator.Tables[0].Rows[0];
int indicatorType = Convert.ToInt32(dr[Common.Systems.Sustainability.Constants.Indicator.IndicatorType]);
if (indicatorType == (int)Common.Systems.Sustainability.Constants.IndicatorTypes.Currency
|| indicatorType == (int)Common.Systems.Sustainability.Constants.IndicatorTypes.Numeric)
{
decimal? total = SumTotal(companyID, indID, indicatorType, fromDate, toDate, formulaOutputUnit, callerIndicatorID, breakToMonthly, specifiedLocations, approvalStatus
, usageDataSet, interval
, indicatorIDsChain
, allowNull
);
expression.Append(total.ToString());
}
else if (symbol == "+"
|| symbol == "-"
|| symbol == "*"
|| symbol == "/")
{
expression.Append(symbol);
}
}
}
else
{
expression.Append(val.ToString());
}
}
else
{
string exp = GetExpression(companyID, fromDate, toDate, referenceIndID.Value.ToString(), indID.ToString(), formulaOutputUnit, breakToMonthly, specifiedLocations, approvalStatus
, usageDataSet, interval
, indicatorIDsChain
);
//expression.Append(exp);
using (DataTable dt = new DataTable())
{
// fault tolerance, for in-case users assigned symbol in the last line of formula
if (exp.EndsWith("+")
|| exp.EndsWith("-")
|| exp.EndsWith("*")
|| exp.EndsWith("/"))
{
exp = exp.Substring(0, exp.Length - 1);
}
object result = dt.Compute(exp, "");
expression.Append(result);
}
} // end if (referenceIndID == null)...
if ("IF".Equals(symbol, StringComparison.OrdinalIgnoreCase)
|| "THEN".Equals(symbol, StringComparison.OrdinalIgnoreCase)
|| "ELSE IF".Equals(symbol, StringComparison.OrdinalIgnoreCase)
|| "ELSE".Equals(symbol, StringComparison.OrdinalIgnoreCase)
|| ">".Equals(symbol, StringComparison.OrdinalIgnoreCase)
|| ">=".Equals(symbol, StringComparison.OrdinalIgnoreCase)
|| "=".Equals(symbol, StringComparison.OrdinalIgnoreCase)
|| "<=".Equals(symbol, StringComparison.OrdinalIgnoreCase)
|| "<".Equals(symbol, StringComparison.OrdinalIgnoreCase)
)
{
//--------------------------------------------------------
// Begin, added by HC on 2016-12-14
// as requested by CQS users, add "IF" statement for GRI indicators
string exp = HandleIFCondition(table, i, companyID, fromDate, toDate, indicatorIDs, callerIndicatorID, callerAcceptedUnit, breakToMonthly, specifiedLocations, approvalStatus, usageDataSet, interval, indicatorIDsChain);
expression.Append(exp);
// End, added by HC on 2016-12-14
//--------------------------------------------------------
// Find End if, added by Alex Poon on 20190306
int ifIndex = i;
for (var j = ifIndex; j < count; j++)
{
string endIfSymbol = Convert.ToString(table.Rows[j][Common.Systems.Sustainability.Constants.IndicatorFormula.Symbol]);
if ("END IF".Equals(endIfSymbol, StringComparison.OrdinalIgnoreCase))
{
i = j;
break;
}
}
}
else
{
if (!string.IsNullOrWhiteSpace(symbol)
&& expression.Length > 0 // added by HC on 2016-06-24
)
{
if (i + 1 >= count && symbol != ")")
{
// ignore the symbol
}
else if (expression.ToString() != symbol)
{
expression.Append(symbol);
}
}
else if (expression.Length == 0 && symbol == "(")
{
expression.Append(symbol);
}
if (symbol == "days")
{
// added by HC on 2017-01-23, a new requirements for calculating average values by days.
if (fromDate != null && toDate != null)
{
int days = toDate.Value.Subtract(fromDate.Value).Days + 1;
expression.Append(days);
}
else
{
expression.Append(1);
}
}
} // end if ("IF".Equals(symbol, StringComparison.OrdinalIgnoreCase)...
if (expDic != null && expression != null)
{
expDic.Add(i, expression.ToString());
}
_sem.Release();
}), f);
taskList.Add(t);
if ("IF".Equals(formulaSymbol, StringComparison.OrdinalIgnoreCase))
{
for (var j = f; j < count; j++)
{
string endIfSymbol = Convert.ToString(table.Rows[j][Common.Systems.Sustainability.Constants.IndicatorFormula.Symbol]);
if ("END IF".Equals(endIfSymbol, StringComparison.OrdinalIgnoreCase))
{
f = j;
break;
}
}
}
}
Task.WaitAll(taskList.ToArray());
List<int> keys = expDic.Keys.ToList();
keys.Sort();
string finalExpression = "";
foreach (var key in keys)
{
finalExpression += expDic[key];
}
return finalExpression;
}
args in your case is data that will be passed to a delegate specified by Action<object> parameter.
See docs.
When using overload of StartNew with Action<object>, you need to supply next argument of type object, which will be used in passed delegate.
Task.Factory.StartNew((o) => {/* 1 will be used here */}, 1, token, options, scheduler);
MSDN
The args argument (referred to as "state" in the documentation) is a parameter you need to specify when you call to Task.Factory.StartNew.
state (Object): An object containing data to be used by the action delegate.
Sample:
object param = somevalue;
Task.Factory.StartNew( (arg) =>
{ /* get the arg value here.*/
}, param);
From a CompactFramework, I got a TypeString which can be a complex type, meaning it can use generics, arrays, etc. That means it can look like Sytem.Tuple’1[[Sytem.String, mscorlib]]. Problem is, I can not use Type.GetType because the assemblys in the Typestring may be wrong or not present.
Is there a lib which parses the string, and returns a type by searching all types in appdomain for the right one?
I've now found no Code, but solved using this:
public static class TypeHelper
{
public static Type GetTypeFromString(string typeString)
{
int pos = 0;
return ParseInternal(typeString, ref pos);
}
private static Type ParseInternal(string name, ref int pos)
{
StringBuilder sb = new StringBuilder();
List<Type> genericParameters = null;
int arrayDimensions = 0;
bool ignore = false;
while (pos < name.Length)
{
char c = name[pos++];
switch (c)
{
case ',':
{
if (arrayDimensions > 0)
arrayDimensions++;
else
ignore = true;
break;
}
case '[':
{
if (name[pos] == '[')
{
if (genericParameters == null)
genericParameters = new List<Type>();
pos++;
genericParameters.Add(ParseInternal(name, ref pos));
}
else if (genericParameters!=null)
genericParameters.Add(ParseInternal(name, ref pos));
else
arrayDimensions++;
break;
}
case ']':
{
var currentName = sb.ToString();
var type = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()).FirstOrDefault(x => x.FullName == currentName);
if (name.Length > pos && name[pos] == ']')
{
pos++;
}
if (genericParameters != null)
{
return type.MakeGenericType(genericParameters.ToArray());
}
else if (arrayDimensions != 0)
{
return type.MakeArrayType(arrayDimensions);
}
return type;
}
default:
if (!ignore)
sb.Append(c);
continue;
}
}
{
var currentName = sb.ToString();
var type = AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()).FirstOrDefault(x => x.FullName == currentName);
if (genericParameters != null)
{
return type.MakeGenericType(genericParameters.ToArray());
}
else if (arrayDimensions != 0)
{
return type.MakeArrayType(arrayDimensions);
}
return type;
}
}
}
I am working on building an expression tree from an infix expression. Currently I am converting to postfix and then building the tree. My code works for most expressions but not all. I am doing something wrong with my implementation of parentheses. Here is my code-
readonly static char[] operators = { '+', '-', '*', '/' };
string order_of_op(string op1, string op2)
{
if (op1 == "*" || op1 == "/")//is op1 higher?
{
return op1;//it is so return it
}
else if ((op2 == "*" || op2 == "/"))//is op2 higher
{
return op2;//it is so return it
}
else
return op1;// they are both addition or subtraction so return op1.
}
Queue<string> convert_to_postfix(string infix) //following the Shunting-yard algorithm
{
Queue<string> num_queue = new Queue<string>();
Stack<string> op_stack = new Stack<string>();
Stack<string> temp_stack = new Stack<string>();
string temp = "";
foreach (char s in infix)
{
if (operators.Contains(s) == true)//if its a function push it on the stack
{
if (temp != "")//make sure we don't push an empty string
num_queue.Enqueue(temp);
if (op_stack.Count != 0)//make sure we dont crash popping from empty stack
{
if (op_stack.Peek() != "(")//if we dont have a parenthese on top proceed as normal
{
if (op_stack.Count > 1)
{
while (op_stack.Count != 0 && order_of_op(op_stack.Peek(), s.ToString()) == op_stack.Peek())
{
num_queue.Enqueue(op_stack.Pop());
}
}
}
op_stack.Push(s.ToString());
}
else
{
op_stack.Push(s.ToString());
}
temp = "";
}
else if (s == '(')
{
op_stack.Push(s.ToString());
}
else if (s == ')')
{
if (temp!= "")
num_queue.Enqueue(temp);
temp = "";
while (op_stack.Peek() != "(")
{
num_queue.Enqueue(op_stack.Pop());
}
op_stack.Pop();
if (op_stack.Count > 1)
{
if (operators.Contains(op_stack.Peek()[0]) == true)
{
num_queue.Enqueue(op_stack.Pop());
}
}
}
else
{
temp += s;
}
}
if (temp != "")
{
num_queue.Enqueue(temp);
}
foreach (string s in op_stack)
{
num_queue.Enqueue(s);
}
Console.Write("Postfix = ");
foreach (string s in num_queue)
{
Console.Write(s);
}
Console.WriteLine();
return num_queue;
}
Thank you for any help!
Well I fixed it! All I had to change was-
if (op_stack.Count > 1)
to
if (op_stack.Count >= 1)