Silverlight Reflection | GetCurrentMethod with passed parameters - c#

I want to print the current method call (incl. return value) to the Visual Studio Output like this:
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
Func<object, object> ret = (value) =>
{
#if DEBUG
var debug = new StringBuilder();
debug.Append("MyConverter.Convert([");
debug.Append(values.Sum(v => (v != null ? v.ToString() : "null") + ',', null, v => v != null ? v.ToString() : "null"));
debug.Append("], " + targetType.ToString() + ", " + parameter.ToString() + ", " + culture.DisplayName + ") =" + value.ToString() + ";");
Debug.WriteLine(debug.ToString());
#endif
return value;
};
// [..]
}
I'm using this sometimes to achieve more informations (e.g. from a Converter as shown here) while debugging. However, that's just a roundabout way.
Is there any way to do it more flexible? Something like GetCurrentArguments (from MethodInfo)?

Since you are using it for debugging there is an option using the StackTrace and StackFrame To get the current method name, but you wont get the arguments, and there is a severe performance penalty.

Related

PropertyInfo.GetValue on Boolean is always True, how to handle False responses

Similar to PropertyInfo.GetValue on Boolean is always True although no useful answer was posted.
I'm using Entity Framework to gather objects from a database and I'm trying to create Json structures as strings. However when gathering boolean answers in the same way as other types, the boolean always returns true.
I've tried to cast the value to a boolean here but I originally tried using the same method as other types (just using value). Is there a reason for this or a fix? Thanks
private static void AppendObjectPropertiesInJson(StringBuilder content, Object obj)
{
content.Append(" {\n");
foreach (PropertyInfo propertyInfo in obj.GetType().GetProperties())
{
var type = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType;
var name = propertyInfo.Name;
var value = propertyInfo.GetValue(obj, null);
if (value == null)
content.Append(" \"" + name + "\": null,\n");
// Error, always returns true
else if (type == typeof(bool))
{
value = (bool)value;
content.Append(" \"" + name + "\": " + value.ToString().ToLower() + ",\n");
}
else if (type == typeof(int))
content.Append(" \"" + name + "\": " + value.ToString().ToLower() + ",\n");
else if (type == typeof(string))
content.Append(" \"" + name + "\": " + "\"" + value.ToString() + "\",\n");
// TODO: Handle arrays
}
content.Append(" },\n");
}
edit: Issue was with unexpected changes in database. Thanks to everybody who helped show there was no issue with this code
The premise of the question is incorrect; PropertyInfo.GetValue works just fine - here used with your method with zero changes:
static void Main()
{
var obj = new Foo { Bar = true, Blap = false };
var sb = new StringBuilder();
AppendObjectPropertiesInJson(sb, obj);
Console.WriteLine(sb);
}
class Foo
{
public bool Bar { get; set; }
public bool Blap { get; set; }
}
outputs the almost-JSON:
{
"Bar": true,
"Blap": false,
},
Note that the expression value = (bool)value is a redundant unbox+box, but: it doesn't change any results (just: it doesn't do anything useful, either).
Note that we can show native bool here too:
else if (type == typeof(bool))
{
var typed = (bool)value;
Console.WriteLine(typed ? "it was true" : "it was false");
// ...content.Append(" \"" + name + "\": " + value.ToString().ToLower() + ",\n");
}
If you have an example where PropertyInfo.GetValue doesn't work, then post that example. Additionally, note that writing your own JSON output is not recommended, as is very easy to get wrong.

If a field contains null then entire concatenate result is null

I am trying to concatenate for a label. If a field contains null then entire concatenate result is null.
[HttpGet]
public ActionResult PMAByPC(string PartnerCode)
{
var result = (from N in _POSContext.PMAs
where (N.PartnerCode == PartnerCode)
select new
{
label = N.Address1 + " | " + N.Address2 + " | " + N.City,
id = N.ID
});
return Json(result);
}
Here, if data is not present in of the fields, label becomes null.
I tried with
select new { label = N.Address1 ?? "?" + " | " + N.Address2 ?? "?" + " | " + N.City ?? "?", id = N.ID }
then it takes only N.Address1 value and ignores the rest of the fields.
Looks like this is a standard SQL string concatenation behavior (the same happens with SqlServer database).
If you want to evaluate the concatenation server side (database), you need to convert null to empty string "" (or something else) using the ?? operator. Similar to your attempt, but you've missed the C# operator precedence. The way you wrote it is equivalent of
N.Address1 ??
(
("?" + " | " + N.Address2) ??
(
("?" + " | " + N.City) ?? "?"
)
)
which is not what was the intent.
You can avoid such issues by enclosing similar conversions with brackets:
select new
{
label = (N.Address1 ?? "?") + " | " + (N.Address2 ?? "?") + " | " + (N.City ?? "?"),
id = N.ID,
}
This is the standard compliant and reasonable behavior: if you concatenate a string with an unknown string, the result is unknown.
Use the coalesce function for that:
coalesce(col1, '') || coalesce(col2, '')

Passing whole function as lambda expression to LINQ

I've getting auctions from my database as:
var auctions = from o in db.auctions select o;
I'd like to pass this function as lambda expression in .Where clause of my linq to filter my auctions result:
private bool wordsHasProductName(auction a, string[] words)
{
if (!a.product_name.Contains(' ')) // Auction product name is single word - check if
{
if (words.Length > 1) return false; // array is passed, single word is searching
else return a.product_name.Contains(words[0]); // check if product name consists passed string
}
else // Auction product name has more words check if passed string is partially in this product name
{
string[] productName = a.product_name.Split(' ');
var list = new List<string>(words);
foreach (string item in productName)
{
if (list.Contains(item)) list.Remove(item);
}
return list.Count == 0;
}
}
I'm calling it in my code, and while debugging there's no error at this line, here's place where I call .Where() clause in linq:
string[] words = searchName.Split(' ');
auctions = auctions.Where((a) => wordsHasProductName(a, words));
But at the end at return statement I'm getting exception error:
return View(auctions.ToPagedList(pageNumber, pageSize));
Error code:
An exception of type 'System.NotSupportedException' occurred in
EntityFramework.SqlServer.dll but was not handled in user code
Additional information: LINQ to Entities does not recognize the method
'Boolean wordsHasProductName(IEP_Projekat.Models.auction,
System.String[])' method, and this method cannot be translated into a
store expression.
How could I succeed sending full bool function as lambda expression in my linq .Where()?
As others already mentioned, method calls cannot be used in LINQ to Entities because they cannot be translated to SQL. So the only possible way would be if you can rewrite the method as compatible expression. And here comes the other problem - you are using string.Split method which is not supported.
So you are out of luck. Or may be not. Here is the trick. Instead of splitting the product_name and checking if it contains every word in words, you can use the following (IMO equivalent) criteria:
words.All(word => (" " + product_name + " ").Contains(" " + word + " "))
Enclosing both product_name and word with space allows you to match the whole word at the beginning, middle or at the end of the target string. And it uses only constructs that are supported by the EF.
Putting it all together. The function would be like this:
private static Expression<Func<auction, bool>> wordsHasProductName(string[] words)
{
if (words.Length == 1)
{
var word = words[0]; // Avoid ArrayIndex not supported
return a => !a.product_name.Contains(" ") && a.product_name.Contains(word);
}
else
{
return a => words.All(word => (" " + a.product_name + " ").Contains(" " + word + " "));
}
}
and the usage:
string[] words = searchName.Split(' ');
auctions = auctions.Where(wordsHasProductName(words));
However the above implementation does not produce very good SQL query, especially for more than one word. A much better SQL is produced if rewriting it by building the predicate expression manually:
private static Expression<Func<auction, bool>> wordsHasProductName(string[] words)
{
Expression<Func<auction, string>> product_name;
Expression condition;
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
if (words.Length == 1)
{
// a => !a.product_name.Contains(" ") && a.product_name.Contains(words[0])
product_name = a => a.product_name;
condition = Expression.AndAlso(
Expression.Not(Expression.Call(product_name.Body, containsMethod, Expression.Constant(" "))),
Expression.Call(product_name.Body, containsMethod, Expression.Constant(words[0])));
}
else
{
// a => (" " + a.product_name + " ").Contains(" " + words[0] + " ")
// && (" " + a.product_name + " ").Contains(" " + words[1] + " ")
// ...
// && (" " + a.product_name + " ").Contains(" " + words[N-1] + " ")
product_name = a => " " + a.product_name + " ";
condition = words
.Select(word => Expression.Call(product_name.Body, containsMethod, Expression.Constant(" " + word + " ")))
.Aggregate<Expression>(Expression.AndAlso);
}
return Expression.Lambda<Func<auction, bool>>(condition, product_name.Parameters);
}
Welcome to the world of EF and expressions :)
You can't pass this complex C# logic as an Expression Tree that can interpreted by the EF provider and the hardest part for the provider is transforming it into SQL statements.
So, your option is to create a stored procedure where you pass in the required parameters, then you write the logic using pure SQL. Then, you map your SP to EF and call it to return the list of objects you want.

What is the replacement Sql Char(13) and isnull in Entity Framework?

I am new to Entity framework, Can any body tell me how to write the following query into Entity framework.
select column1 + char(13) +isnull(column2,space(1))+char(13)+isnull(column3,space(1))+char(13)+isnull(column4,space(1)) +char(13)+isnull(olumn5,space(1)) as FADRS
FROM table
Convert the above query into Entity Framework.
By using Jon answer i get the answer. Know my problem is how to use iqueryable
IQuer<string> Madr = from b in context.table
where b.column1 == txtaddrss.Text
select new
{FADR = b.column2 + '\r' +
(b.column3 ?? " ") + '\r' +
(b.column4 ?? " ") + '\r' +
(b.column5 ?? " ") + '\r' +
(b.column6 ?? " ")};
foreach(string something in Madr)
{
MessageBox.Show(something);
}
i am getting error conversion failed because of anonymous type
char(13) just does the equivalent (though more limited) of (char)13 in C#, which would just return '\r'.
Hence you would either use '\r' or "\r".
isnull(x, y)just does the equivalent of x ?? y in C#.
So you would use something like:
var query = from item in TableSource select
item.column1 + '\r' +
(item.column2 ?? " ") + '\r' +
(item.column3 ?? " ") + '\r' +
(item.column4 ?? " ") + '\r' +
(item.column5 ?? " ");
TableSource is whatever way you are getting a reference to the table (context.Table or whatever).
query will be an IQueryable<string> returning the relevant strings when invoked. If you really want the FADRS name from your example then the following will instead of strings return anonymous objects with a FADRS property:
var query = from item in TableSource select
new {FADRS = item.column1 + '\r' +
(item.column2 ?? " ") + '\r' +
(item.column3 ?? " ") + '\r' +
(item.column4 ?? " ") + '\r' +
(item.column5 ?? " ")};
Edit:
The first example above can be used as:
foreach(string something in query)
MessageBox.Show(something);
The second example as:
foreach(var something in query)
MessageBox.Show(something.FADR);
With the first var is optional shorthand, with the second you must use var as the types involved are anonymous, and hence var is the only way to name the type (by not naming it at all).
Given no further context I'd say sonething like this:
var query = from obj in context.table
select new {
FADR = obj.column1 + "\r" +
obj.column2 ?? " " + "\r" +
obj.column3 ?? " " + "\r" +
obj.column4 ?? " " + "\r" +
obj.column5 ?? " " + "\r" };

NullReferenceException in string.IsNullOrWhiteSpace() and string.IsNullOrEmpty()

I'm checking the cell values of cells of a column that might or not be empty/null so I needed something to avoid a NullReferenceException.
How do I do that since even with the IsNullOrWhiteSpace() and IsNullOrEmpty() I get that exception somehow.
Here's part of the code I'm using:
s = "Total = " + dataGridView1.Rows[0].Cells.Count +
"0 = " + dataGridView1.Rows[0].Cells[0].Value.ToString() +
"/n 1 = " + dataGridView1.Rows[0].Cells[1].Value.ToString() +
"/n 2= " + dataGridView1.Rows[0].Cells[2].Value.ToString() +
"/n 3 = " + dataGridView1.Rows[0].Cells[3].Value.ToString() +
"/n 4= " + dataGridView1.Rows[0].Cells[4].Value.ToString() +
"/n 5 = " + dataGridView1.Rows[0].Cells[5].Value.ToString() +
"/n 6= " + dataGridView1.Rows[0].Cells[6].Value.ToString() +
"/n 7 = " + dataGridView1.Rows[0].Cells[7].Value.ToString();
if (string.IsNullOrEmpty(dataGridView1.Rows[0].Cells[8].Value.ToString()))
{
}
else
{
s += "/n 8 = " + dataGridView1.Rows[0].Cells[8].Value.ToString();
}
I've tried those methods I've tried putting it ==null, I've tried !=null. What else is there or what am I doing wrong exactly and how do I do it right?
the are a lot of places you code could throw that exception ..
dataGridView1.Rows[0] //here
.Cells[0] //here
.Value //and here
.ToString()
I belive you don't need the ToString() just type:
"... "+ dataGridView1.Rows[0].Cells[0].Value
in your ifstatement do this:
if (string.IsNullOrEmpty(dataGridView1.Rows[0].Cells[8].Value as string))
Many people don't understand how to diagnose a NullReferenceException. Consider the following:
dataGridView1.Rows[0].Cells[3].Value.ToString()
Many parts of this could be null. It's the same thing as
var a = dataGridView1.Rows;
var b = a[0];
var c = b.Cells;
var d = c[3];
var e = d.Value;
var f = e.ToString();
If a is null, then a[0] will throw a NullReferenceException. If b is null, then b.Cells will throw a NullReferenceException, etc.
You simply have to figure out which of these is null in your particular situation. The simplest way is to use the debugger. Set a breakpoint before the line that throws the exception. Then hover the mouse over various parts of the expression to see which are null, or use the "Watch" window to enter parts of the expression.
When you find a null, you can stop looking for your NullReferenceException.
You can add an extra line of code to check and handle the null case.
var value = dataGridView1.Rows[0].Cells[0].Value;
string s = (value == null ? string.Empty : value.ToString());
If value is null, then ToString() will not be evaluated and the program cannot throw NullReferenceException.
I think in dataGridView1.Rows[0].Cells[8].Value.ToString() you will get a NullReferenceException if the Value is null. So you should check for dataGridView1.Rows[0].Cells[8].Value != null and then you can convert it to a string

Categories

Resources