I'm getting this:
private object setReportValues(object report, FormCollection values)
{
PropertyInfo[] properties = report.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
string val = values.GetValue(property.Name).ToString();
property.SetValue(report, val, null);
}
return report;
}
Exception is on string val = values.GetValue(property.Name).ToString();. Do I have to check for nulls before?
Do I have to check for nulls before?
On this line, yes:
string val = values.GetValue(property.Name).ToString()
Simply because the value of that particular property could be null.
I'm gonna go out on a limb and suggest that there's no property with the provided property.Name in values. So your call to values.GetValue returns a null. When you try to do ToString() on that null value, it complains.
In short, what does your values variable contain?
Update:
With the provided information that values is a FormsCollection it is quite probable that your properties collection contains a few properties for which you have no FormsCollection field. And what happens is that you try to get this field, it returns a null value and you call ToString on that, causing everything to break.
I would invert my strategy and loop through my FormsCollection getting the properties 1 by 1 as you encounter them. The alternative is to keep it as you have it and check for null before doing a ToString.
PS: I hope all of your properties represented on the form are strings, or things will break.
Just ran into this same issue, but I found a solution without having to use a loop:
private object setReportValues(object report, FormCollection values)
{
PropertyInfo[] properties = report.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
string val = values.GetValue(property.Name)?.ToString();
property.SetValue(report, val, null);
}
return report;
}
I fixed it by adding a ? (new feature in C# 6.0 I believe) after the ...property.Name).
Why would you force .ToString() ? null is a perfectly legal value for most things. It isn't clear what values is, so I assume that is coming from your own code, but:
object val = values.GetValue(property.Name);
property.SetValue(report, val, null);
Depending on what values is, you might also want to check the difference between "has a value, that is null" vs "doesn't have any defined value". Personally, I would expect to do something like:
object val;
if(values.TryGetValue(property.Name, out val)) {
property.SetValue(report, val, null);
}
Related
I am trying to determine the difference between a DateTime and a DateTime? using reflection. Please see my test code below:
public class TestClass
{
public DateTime testDate1 { get; set; }
public DateTime? testDate2 { get; set; }
}
public void Test()
{
TestClass testing = new TestClass();
var props = typeof(TestClass).GetProperties();
foreach (PropertyInfo p in props)
{
object o = p.GetValue(testing);
if (typeof(DateTime?).IsInstanceOfType(o))
{
o = DateTime.Now;
}
if (typeof(DateTime).IsInstanceOfType(o))
{
if (((DateTime)o) == DateTime.MinValue)
{
o = null;
}
}
Console.WriteLine(string.Format("{0} = {1}", p.Name, (o ?? "NULL").ToString()));
}
}
The output of this code is the opposite to what i would expect. Currently the output is:
testDate1 = 26/01/2016 16:15:00
testDate2 = NULL
I am expecting testDate1 to be null and testDate2 to contain the value.
When debugging this code, it seems that the first pass using testDate1 passes both of the typeof if statements, the second fails both of the if statements. Can anybody help me understand and hopefully try and catch the specific nullable instance of the date time?
To note i have also tried switching to a definition and test on Nullable just in case, but it made no difference.
Many thanks!
First, keep in mind that testDate1 can never be null because DateTime is a struct. If you declare a DateTime without intitializing it, it will get the default value of DateTime.MinValue. testDate2, on the other hand, is a Nullable struct, where the default value is null(-ish... it's actually a value that represents null, but not null itself).
IsInstanceOfType is using o's GetType() method in the background to verify that its type is the same as the type you are comparing to (in this case, DateTime?). However, if you take a look at the documentation, it states:
Calling GetType on a Nullable type causes a boxing operation to be performed when the type is implicitly converted to Object. Therefore GetType always returns a Type object that represents the underlying type, not the Nullable type.
So, if you step through the foreach loop for the testDate1 property, you'll see that the first condition will return true (since testDate1 can't be null, which means it has to be of type DateTime). You then step into the second if-condition (though that's effectively just doing the same check again), but you don't enter the inner if because o currently has a value of DateTime.Now.
Now stepping through for testDate2 (which is holds a null value), you will see that you don't enter either of the if-conditionals because null doesn't have a type. As such, your object will remain null throughout the second iteration of the loop, giving you the output you see there.
NOTE: Just so you know, the way you're "assigning" values to o doesn't modify the original TestClass at all. Consider the following:
TestClass testing = new TestClass();
var prop = typeof(TestClass).GetProperty("testDate1");
// Here we get the current value of testing.testDate1, which is the default DateTime.MinValue
object o = prop.GetValue(testing);
// Here we set o to null... has ZERO effect on testing.testDate1.
o = null;
// What you actually want is probably the following.
// (Remember though that testDate1 can't be null... this just sets it back to DateTime.MinValue.)
prop.SetValue(testing, null);
The answer is you can't.
If you have an object date there is no way to know if it orginally comes from a nullabe DateTime or not.
DateTime? nullable = DateTime.Now;
object o = nullable;
The assignment to o is morally equivalent to
object temp = null;
if (nullable.HasValue)
{
temp = nullable.Value;
}
o = temp;
As you can see, the information of the nullable type is lost and what you are really getting is the boxed nullable's value.
This is easy to see by simply doing o.GetType() which will return DateTime if the nullable had a value or you will get a NullReferenceException if it didn't.
This does not mean that you can not determine if the declared type of a property, method or member is nullable or not. You can do this easily enough via reflection.
Thank you for so much useful comments and links. I realise that it was the property i should have been inspecting and not the object. I am using this:
Nullable.GetUnderlyingType(p.PropertyType)
It allows me to determine what i am dealing with and is pretty effective. I still end up switching on typeof(T).Name but i will cross that bridge when i come to it :)
I have to live with the fact that functional code vs ugly code remains an internal battle!
This question already has answers here:
C# Pass a property by reference
(8 answers)
Closed 8 years ago.
I have a process that I want to apply to multiple value-type properties of an arbitrary object, such that each property is modified in some way by the process. A method that applies the process to any given property passed to it would seem to be the way to go, but because the property is a value type it doesn't get changed unless I pass it by reference, but of course the C# compiler prevents properties being passed by reference.
How can I achieve the following without the compiler objecting or having to write messy multiple lines that just repeat the same conditional code for each property?
static internal void AssignStringValueOrLeaveIfNull(string newValue, string sampleValue)
{
if (!string.IsNullOrEmpty(newValue))
sampleValue = newValue;
}
...
AssignStringValueOrLeaveIfNull(value1, anObject.SampleText1);
AssignStringValueOrLeaveIfNull(value2, anObject.SampleText2);
AssignStringValueOrLeaveIfNull(value3, anObject.SampleText3);
AssignStringValueOrLeaveIfNull(value4, anObject.SampleText4);
AssignStringValueOrLeaveIfNull(value5, anObject.SampleText5);
...etc, 30 times.
where anObject.SampleTextn are all strings.
I can't be the first person to have wanted to do something similar!
I'm using VS2008 (C#3.5)
TIA
You cannot. That concept does not exist. You would have to assign the value to a temporary local variable, use ref on the variable, and then assign it back to the property:
var tmp = anObject.SampleText1;
AssignStringValueOrLeaveIfNull(value1, ref tmp);
anObject.SampleText1 = tmp;
Or use a return value, which is probably simpler...
anObject.SampleText1 = AssignStringValueOrLeaveIfNull(value1, anObject.SampleText1);
ref works with:
fields
local variables
array elements
parameters
It does not work with properties, since properties are actually method calls, and the result of a method call does not have a sensible location to ref it from. Note: at the IL level, you can have ref return values from methods, which would theoretically allow for something akin to this - but it is not exposed in C# at the moment (if ever), and it would not work with properties as they exist today.
You could write an ugly extension method that takes an expression representative of the property you want to set, and give it a chance to check whether your new values are null or empty (or different from the destination) before assigning the value.
public static void SetPropertyValue<T>(this T target, Expression<Func<T, string>> memberLamda, string value)
{
// Check if "new value" is null or empty and bail if so
if (string.IsNullOrEmpty(value))
return;
var memberSelectorExpression = memberLamda.Body as MemberExpression;
if (memberSelectorExpression != null)
{
var property = memberSelectorExpression.Member as PropertyInfo;
if (property != null)
{
// Get the existing value and compare against the new value
// Only set the property if it's different from the existing value
if ((string)property.GetValue(target, null) != value)
{
property.SetValue(target, value, null);
}
}
}
}
Source
And then you could use it like:
anObject.SetPropertyValue(a => a.SampleText1, value1);
anObject.SetPropertyValue(a => a.SampleText2, value2);
This should allow you to avoid having the object marked as "dirty", but is rather expensive (as Marc mentioned in a comment on his answer).
I want to check if a variable is initialized at run time, programmatically. To make the reasons for this less mysterious, please see the following incomplete code:
string s;
if (someCondition) s = someValue;
if (someOtherCondition) s = someOtherValue;
bool sIsUninitialized = /* assign value correctly */;
if (!sIsUninitialized) Console.WriteLine(s) else throw new Exception("Please initialize s.");
And complete the relevant bit.
One hacky solution is to initialize s with a default value:
string s = "zanzibar";
And then check if it changed:
bool sIsUninitialized = s == "zanzibar";
However, what if someValue or someOtherValue happen to be "zanzibar" as well? Then I have a bug. Any better way?
Code won't even compile if the compiler knows a variable hasn't been initialized.
string s;
if (condition) s = "test";
// compiler error here: use of unassigned local variable 's'
if (s == null) Console.Writeline("uninitialized");
In other cases you could use the default keyword if a variable may not have been initialized. For example, in the following case:
class X
{
private string s;
public void Y()
{
Console.WriteLine(s == default(string)); // this evaluates to true
}
}
The documentation states that default(T) will give null for reference types, and 0 for value types. So as pointed out in the comments, this is really just the same as checking for null.
This all obscures the fact that you should really initialize variables, to null or whatever, when they are first declared.
With C# 2.0, you have the Nullable operator that allows you to set an initial value of null for heretofore value types, allowing for such things as:
int? x = null;
if (x.HasValue)
{
Console.WriteLine("Value for x: " + num.Value);
}
Which yields:
"Value for x: Null".
Just assign it null by default, not a string value
Here's one way:
string s;
if (someCondition) { s = someValue; }
else if (someOtherCondition) { s = someOtherValue; }
else { throw new Exception("Please initialize s."); }
Console.WriteLine(s)
This might be preferable for checking if the string is null, because maybe someValue is a method that can sometimes return null. In other words, maybe null is a legitimate value to initialize the string to.
Personally I like this better than an isInitialized flag. Why introduce an extra flag variable unless you have to? I don't think it is more readable.
You can keep a separate flag that indicates that the string has been initialized:
string s = null;
bool init = false;
if (conditionOne) {
s = someValueOne;
init = true;
}
if (conditionTwo) {
s = someValueTwo;
init = true;
}
if (!init) {
...
}
This will take care of situations when s is assigned, including the cases when it is assigned null, empty string, or "zanzibar".
Another solution is to make a static string to denote "uninitialized" value, and use Object.ReferenceEquals instead of == to check if it has changed. However, the bool variable approach expresses your intent a lot more explicitly.
I would agree with Vytalyi that a default value of null should be used when possible, however, not all types (like int) are nullable. You could allocate the variable as a nullable type as explained by David W, but this could break a lot of code in a large codebase due to having to refine the nullable type to its primitive type before access.
This generic method extension should help for those who deal with large codebases where major design decisions were already made by a predecessor:
public static bool IsDefault<T>(this T value)
=> ((object) value == (object) default(T));
If you are staring from scratch, just take advantage of nullable types and initialize it as null; that C# feature was implemented for a reason.
I pick initialization values that can never be used, typical values include String.Empty, null, -1, and a 256 character random string generator .
In general, assign the default to be null or String.Empty. For situations where you cannot use those "empty" values, define a constant to represent your application-specific uninitialized value:
const string UninitializedString = "zanzibar";
Then reference that value whenever you want to initialize or test for initialization:
string foo = UnininitializedString;
if (foo == UninitiaizedString) {
// Do something
}
Remember that strings are immutable constants in C# so there is really only one instance of UninitializedString (which is why the comparison works).
I've been investigating the out keyword in C# after reading the section about it in C# in Depth. I cannot seem to find an example that shows why the keyword is required over just assigning the value of a return statement. For example:
public void Function1(int input, out int output)
{
output = input * 5;
}
public int Function2(int input)
{
return input * 5;
}
...
int i;
int j;
Function1(5, out i);
j = Function2(5);
Both i and j now have the same value. Is it just the convenience of being able to initialize without the = sign or is there some other value derived that I'm not seeing? I've seen some similar answers mentioning that it shifts responsibility for initialization to the callee here. But all that extra instead of just assigning a return value and not having a void method signature?
Usually out is used for a method that returns something else, but you still need to get a different value from the method.
A good example is Int32.TryParse(input, out myVar) it will return true if it was successful and false otherwise. You can get the converted int via the out parameter.
int myOutVar;
if (Int32.TryParse("2", out myOutVar))
{
//do something with the int
}else{
//Parsing failed, show a message
}
The out / ref keywords in C# should only be used when you need to return multiple values. Even then you should first consider using a container type (such as Tuple) to return multiple values before you revert to out / ref. Whenever you're returning a single value it should just be returned.
A lot of times, using out can help by giving you a slight performance gain.
Consider the TryGetValue method on IDictionary (say myDictionary is an IDictionary<string, string>) Rather than doing this:
string value = String.Empty;
if (myDictionary.ContainsKey("foo"))
{
value = myDictionary["foo"];
}
Both ContainsKey and the indexer need to look up the key in the dictionary, but you can avoid this double-lookup on the positive case by going:
string value;
if (!myDictionary.TryGetValue("foo", out value))
{
value = String.Empty;
}
IMO, that's a decent reason for using out parameters.
Unfortunately we cannot do something like below in C#:
a,b = func(x,y,z);
something that we do in Python or other languages. out kind of overcomes that.
F# has overcome this with tuples I believe.
PS: Returning multiple values from a function might not be good always. Tiny types are good most of the times - http://www.martinfowler.com/bliki/DataClump.html
For example, Int32.TryParse returns boolean if it parsed correctly and with the out parameter changes the value. If the parsed value is 0 and it returns true it means the value you sent to parse was 0. If it returns false then the parser failed.
Some of it is for clarity. Take the TryParse() methods, like
Int32.TryParse("3", out myInt);
This returns a bool that indicates whether the string was able to be parsed into an int.
If you just had
Int32.TryParse("3", myInt);
What happens when that's called? Is myInt assigned? Does TryParse return an int?
It's not readily apparent. But if I have an out parameter, then I know that the value is getting assigned, and that the return is something else.
Basically you do something like (my database read)
if (ReadSingle<UserRecord>(cmd, out user))
Cache.Insert(cacheId, user, null,
DateTime.MaxValue, TimeSpan.FromMinutes(3));
Or else you do something like:
user = ReadSingle<UserRecord>(cmd);
if(null != user)
// Cache.Insert ...
It simplifies the code a little to use a boolean result (that a record was read from the database) and get the actual record into the variable via the out keyword.
I'm getting the above error and unable to resolve it.
I googled a bit but can't get rid of it.
Scenario:
I have class BudgetAllocate whose property is budget which is of double type.
In my dataAccessLayer,
In one of my classes I am trying to do this:
double.TryParse(objReader[i].ToString(), out bd.Budget);
Which is throwing this error:
Property or indexer may not be passed as an out or ref parameter at
compile time.
I even tried this:
double.TryParse(objReader[i].ToString().Equals(DBNull.Value) ? "" : objReader[i].ToString(), out bd.Budget);
Everything else is working fine and references between layers are present.
Others have given you the solution, but as to why this is necessary: a property is just syntactic sugar for a method.
For example, when you declare a property called Name with a getter and setter, under the hood the compiler actually generates methods called get_Name() and set_Name(value). Then, when you read from and write to this property, the compiler translates these operations into calls to those generated methods.
When you consider this, it becomes obvious why you can't pass a property as an output parameter - you would actually be passing a reference to a method, rather than a reference to an object a variable, which is what an output parameter expects.
A similar case exists for indexers.
This is a case of a leaky abstraction. A property is actually a method, the get and set accessors for an indexer get compiled to get_Index() and set_Index methods. The compiler does a terrific job hiding that fact, it automatically translates an assignment to a property to the corresponding set_Xxx() method for example.
But this goes belly up when you pass a method parameter by reference. That requires the JIT compiler to pass a pointer to the memory location of the passed argument. Problem is, there isn't one, assigning the value of a property requires calling the setter method. The called method cannot tell the difference between a passed variable vs a passed property and can thus not know whether a method call is required.
Notable is that this actually works in VB.NET. For example:
Class Example
Public Property Prop As Integer
Public Sub Test(ByRef arg As Integer)
arg = 42
End Sub
Public Sub Run()
Test(Prop) '' No problem
End Sub
End Class
The VB.NET compiler solves this by automatically generating this code for the Run method, expressed in C#:
int temp = Prop;
Test(ref temp);
Prop = temp;
Which is the workaround you can use as well. Not quite sure why the C# team didn't use the same approach. Possibly because they didn't want to hide the potentially expensive getter and setter calls. Or the completely undiagnosable behavior you'll get when the setter has side-effects that change the property value, they'll disappear after the assignment. Classic difference between C# and VB.NET, C# is "no surprises", VB.NET is "make it work if you can".
you cannot use
double.TryParse(objReader[i].ToString(), out bd.Budget);
replace bd.Budget with some variable.
double k;
double.TryParse(objReader[i].ToString(), out k);
Possibly of interest - you could write your own:
//double.TryParse(, out bd.Budget);
bool result = TryParse(s, value => bd.Budget = value);
}
public bool TryParse(string s, Action<double> setValue)
{
double value;
var result = double.TryParse(s, out value);
if (result) setValue(value);
return result;
}
Place the out parameter into a local variable and then set the variable into bd.Budget:
double tempVar = 0.0;
if (double.TryParse(objReader[i].ToString(), out tempVar))
{
bd.Budget = tempVar;
}
Update: Straight from MSDN:
Properties are not variables and
therefore cannot be passed as out
parameters.
This is a very old post, but I'm ammending the accepted, because there is an even more convienient way of doing this which I didn't know.
It's called inline declaration and might have always been available (as in using statements) or it might have been added with C#6.0 or C#7.0 for such cases, not sure, but works like a charm anyway:
Inetad of this
double temp;
double.TryParse(objReader[i].ToString(), out temp);
bd.Budget = temp;
use this:
double.TryParse(objReader[i].ToString(), out double temp);
bd.Budget = temp;
So Budget is a property, correct?
Rather first set it to a local variable, and then set the property value to that.
double t = 0;
double.TryParse(objReader[i].ToString(), out t);
bd.Budget = t;
Usually when I'm trying to do this it's because I want to set my property or leave it at the default value. With the help of this answer and dynamic types we can easily create a string extension method to keep it one lined and simple.
public static dynamic ParseAny(this string text, Type type)
{
var converter = TypeDescriptor.GetConverter(type);
if (converter != null && converter.IsValid(text))
return converter.ConvertFromString(text);
else
return Activator.CreateInstance(type);
}
Use like so;
bd.Budget = objReader[i].ToString().ParseAny(typeof(double));
// Examples
int intTest = "1234".ParseAny(typeof(int)); // Result: 1234
double doubleTest = "12.34".ParseAny(typeof(double)); // Result: 12.34
decimal pass = "12.34".ParseAny(typeof(decimal)); // Result: 12.34
decimal fail = "abc".ParseAny(typeof(decimal)); // Result: 0
string nullStr = null;
decimal failedNull = nullStr.ParseAny(typeof(decimal)); // Result: 0
Optional
On a side note, if that's an SQLDataReader you may also make use of GetSafeString extension(s) to avoid null exceptions from the reader.
public static string GetSafeString(this SqlDataReader reader, int colIndex)
{
if (!reader.IsDBNull(colIndex))
return reader.GetString(colIndex);
return string.Empty;
}
public static string GetSafeString(this SqlDataReader reader, string colName)
{
int colIndex = reader.GetOrdinal(colName);
if (!reader.IsDBNull(colIndex))
return reader.GetString(colIndex);
return string.Empty;
}
Use like so;
bd.Budget = objReader.GetSafeString(i).ParseAny(typeof(double));
bd.Budget = objReader.GetSafeString("ColumnName").ParseAny(typeof(double));
I had the same problem (5 minutes ago) and I solved it using old style properties with getter and setter, whose use variables.
My code:
public List<int> bigField = new List<int>();
public List<int> BigField { get { return bigField; } set { bigField = value; } }
So, I just used bigField variable. I'm not the programmer, if I misunderstood the question, I'm really sorry.