C# get property value with reflection has not default value - c#

I have this code:
messageDto = new CorrelationDto()
{
timestamp = default,
};
var isDefault = messageDto.GetType().GetProperty("timestamp").GetValue(messageDto) == default; // FALSE
var isDefault2 = messageDto.timestamp == default; // TRUE
where timestamp is a DateTime.
As you can see, getting the value through reflection and comparing to default return false. Do you have any idea why it's happening and how should I do to check for default values?
Thanks
== EDIT ==
It has been pointed to me that the return value of GetValue() is an object and so it must be casted to DateTime in order for the default to work. Unfortunately I cannot because I'm running this test on all the properties of an object to discover if this object is initialized or not (so I check for null or default value). And the messageDto in reality is a generic type so I don't know the types of its properties a priori.

GetValue returns an object of type object, because it can't know at compile time what the type of the property is. The default value of an object is null, but since DateTime is a value type, its default value cannot be null.
Cast the result of GetValue to DateTime.

If I correctly understood you, this is how I solved this problem:
private static bool IsValueNumericDefault(object value)
{
var intVal = 1;
var doubleVal = 1.0;
return (int.TryParse($"{value}", out intVal) || double.TryParse($"{value}", out doubleVal)) &&
(intVal == default || doubleVal == default);
}
I check random object value through casting it to string and try parse to type that I check. Value parameter is returned by reflection method .GetValue(). You can try to parse it to DateTime or any other type that you check.

Related

C# DateTime Submit method

Can anyone help me to figure out as to why I am getting this error message, when I didn't enter in any date or time when I click the submit button?
An exception of type 'System.InvalidOperationException' occurred in
mscorlib.dll but was not handled in user code Additional information:
Nullable object must have a value.
int result1 = this.startDate.SelectedDate.Value.Date.CompareTo(DateTime.Now.Date);
int result2 = this.endDate.SelectedDate.Value.Date.CompareTo(this.startDate.SelectedDate.Value.Date);
if (result1 >= 0 && result2 > 0)
{
//To Do navigate to sprint dashboard
// var userProjects = new UserStory();
//var sprintDashboardPage = new SprintDashboardPage(usersProjects);
//var mainWindow = this.GetWindow() as MainWindow;
//mainWindow.MainFrame.Navigate(sprintDashboardPage);
this.ErrorMessage = "Date is VALID";
this.CloseWindow();
}
else
{
this.ErrorMessage = "Choose Valid Date";
}
this.startDate.SelectedDate is a Nullable<DateTime>. This means you have to check whether this.startDate.SelectedDate has a value assigned before using it by doing:
if(this.startDate.SelectedDate.HasValue) {
this.startDate.SelectedDate.Value.Date.CompareTo(DateTime.Now.Date);
}
The following will also work:
if(this.startDate.SelectedDate != null) {
this.startDate.SelectedDate.Value.Date.CompareTo(DateTime.Now.Date);
}
Same applies when accessing this.endDate.SelectedDate.
In C#, DateTime is Value Type which means it must always have a value assigned to it. In other words, it can't be set to null. Its default value is DateTime.MinValue. Int32 (or int) is another example of a Value Type and it's default value is 0.
In order to make a Value Type support null, you can wrap it with Nullable<>. Doing so means that you have to explicitly check whether a value has been assigned before accessing the value, or an InvalidOperationException will be thrown.
The DateTime picker control in WPF returns a Nullable<DateTime> object so that you can know whether a user has actually selected a value in the control, as it will be set a non-null value.
You're calling the Value property on a Nullable<> without first checking its HasValue property returns true.
The exception is thrown in the .Value property of the DateTime? (nullable DateTime), as it is required to return a DateTime, but it can't because there's no DateTime to return.
It is a bad idea to access .Value property of Nullable type without checking it. You should consider adding null-checking code. ( e.g. with HasValue property )

IsNull() extention for checking null value for any object

I am adding new extension method for checking null value for any object on following criteria:
Should return true if value for class object is null
Should return true if object is of type string and having value null or Empty
Should return true if object is of type DateTime and having Min value.
Any other condition for null need to check.(Please suggest if required.)
Here is IsNull() extention method:
public static bool IsNull(this object obj)
{
if (obj == null || obj == DBNull.Value)
return true;
if (obj.GetType() == typeof(string))
return string.IsNullOrEmpty(obj.ToString());
if (obj.GetType() == typeof(DateTime))
{
DateTime _dateValue = DateTime.MinValue;
if (DateTime.TryParse(obj.ToString(), out _dateValue) && _dateValue == DateTime.MinValue)
return true;
}
return false;
}
Now my question is:
Do I need to add check differently for Value and Reference type
object?
Does this extension method handle all type of null check for any
object?
Any suggestion or improvement need to add in extension?
Do I need to add check differenty for Value and Reference type object?
Value types can not be null.
Does this externtion method handle all type of null check for any object?
It looks like (except value types)
Any suggestion or improvement need to add in extention?
As I said value types cannot be null, so you can add an extra condition to check whether the type is value type or not,if so you can return false
if(obj.GetType().IsValueType) return false;
By the way if you write this before the DateTime check,your DateTime condition will become unreachable.It doesn't make sense anyway but it's your choice.If you want to return true when the value equals to DateTime.MinValue it's completely up to you.
A few observations:
1) A value type will never be null. When called on a value type.. it will be boxed to an object.. and won't be null (unless you wrap it in a Nullable<T>).
2) Your method no longer checks for null.. it also checks for a minimum value and empty strings. An empty string is not null - its an empty value. A minimum value is not null.. its a value. It has too much responsibility here and should be renamed.
3) Given what I've said above.. you could just simply do this instead of writing your own function:
if (variable == default(variable.GetType()))
Since that checks for the default of all types.. value types such as DateTime, int, and classes for null. Then, your only other specific check is for DBNull.Value.

Check if an Object has something or not

I have the following property:
IDictionary<string, object> Values { get; }
The property has a few values having one of them the key "culture".
I tried to use that value and casting to a string:
String value = (String)data.Values["culture"] ?? defaultCulture;
This works when the item has some value but when it doesn't I get the error:
Unable to cast object of type 'System.Web.Mvc.UrlParameter' to type 'System.String'.
BTW, System.Web.Mvc.UrlParameter:
http://msdn.microsoft.com/en-us/library/system.web.mvc.urlparameter%28v=vs.108%29.aspx
In the debugger data.Values["culture"] has the value {}. I tested and:
var test_1 = data.Values["culture"] == null; // returns false
var test_2 = data.Values["culture"].ToString() == null; // returns false
How do I check if data.Values["culture"] has something in it or not?
Apparently, you are storing a UrlParameter in that dictionary entry. If you want to get a string out, you will need to use ToString().
The exact expression to use will depend on the type of defaultCulture. If it is a string, then
String value = data.Values["culture"] == null ? defaultCulture : data.Values["culture"].ToString();
if it is a UrlParameter, then
String value = (data.Values["culture"] ?? defaultCulture).ToString();
If you want to get the string if it indeed is a string and a default value otherwise, you can test the type of the valuer using as. Something like:
(data.Values["culture"] as string) ?? defaultCulture
Try this:
String value = (String) (data.Values["culture"] ?? defaultCulture);
The idea is to check for null before trying to cast.
did you use this?
string.IsNullOrWhiteSpace(somestring)

How to i return the value of a property if i dont know the propertyname at run-time?

And let's assume for simplicity that the value of the property needs to always be returned as a string.
public string GetTheValueOfTheProperty(PropertyInfo propertyInfo,Object myObject){
string propname = propertyInfo.Name;
if (propName == "IsSelected"){
return myObject.IsSelected.ToString();
}
//...
}
This works, but it doesn't work if I don't know the name of the property. How would I do that in that scenario ?
http://msdn.microsoft.com/en-us/library/system.reflection.propertyinfo.getvalue.aspx
You can call propertyInfo.GetValue(myObject, null);.
You can convert to a string with ToString(), but you should check for null values first - otherwise you'll get a NullReferenceException.
The PropertyInfo object lets you invoke the property on the object:
object value = propertyInfo.GetGetMethod().Invoke(myObject, new object[] { });

What's the recommended way to start using types from a returned DataRow in C#?

When looping through a DataRow and encountering types such as
DataRow dr;
dr["someString"]
dr["someInteger"]
dr["somedata"]
What's the best way to get them into their corresponding data types? dr["foo"] is just a generic object.
Also, are these able to be easily converted to nullable types? dr["someInteger"] could be null.
When reading from a DataRow, your biggest enemy is a null value. In a DataRow, when a value is null, it is not equals to null: It is equals to DBNull.Value.
if(DBNull.Value == null)
{
// Will never happen
}
Unless you know that your field cannot be null, it is not safe to cast. For example, the following example will fail if the data is DBNull:
string name = (string)dr["Name"];
If you can use the LINQ extensions, you can include the reference System.Data.DataSetExtensions and the namespace System.Data and call
string name = dr.Field<string>("Name");
If you cannot use LINQ, then you have to fall back to checking for null value with
string name = null;
if(!dr.IsNull("Name"))
name = (string)dr["Name"];
Or you could code your own Field function like this:
public static T GetValue<T>(object value)
{
if (value == null || value == DBNull.Value)
return default(T);
else
return (T)value;
}
and get your value this way:
string name = GetValue<string>(dr["Name"]);
If you can use .net 3.5, then you can use the Field extension method to more easily access the data if you know the type. An example would be:
string somestring= row.Field<string>("SomeString");
Otherwise you're stuck with casting the field to the type of the object the old fashioned way.
Simply casting the values to the right type should work:
(string) dr["someString"];
(int?) dr["someInteger"];
(byte[]) dr["somedata"];
string GetString(DataRow dr, string ColumnName)
{
if (dr.IsNull(ColumnName))
{
return null;
}
return (string)dr[ColumnName];
}
Another option is to use "as"
string str = dr["someString"] as string;
if it's DBNull.Value (or any other object not of type string), then str will get a real "null". Otherwise it will get the proper string value.
For value types, you can use nullable, i.e.
int? i = dr["someint"] as int?;
Again, it will get a real "null" instead of DBNull.Value. However, with nullable types you have to remember to use .Value, i.e.
int x = i.Value + 5;

Categories