Determine value of object in C# - c#

What would be the best way to determine if an object equals number zero (0) or string.empty in C#?
EDIT: The object can equal any built-in System.Value type or reference type.
Source Code:
public void MyMethod(object input1, object input2)
{
bool result = false;
object compare = new object();
if(input != null && input2 != null)
{
if(input1 is IComparable && input2 is IComparable)
{
//do check for zero or string.empty
//if input1 equals to zero or string.empty
result = object.Equals(input2);
//if input1 not equals to zero or string.empty
result = object.Equals(input1) && object.Equals(input2); //yes not valid, but this is what I want to accomplish
}
}
}

Using Jonathan Holland code sample with a minor modification, here is the solution that worked:
static bool IsZeroOrEmpty(object o1)
{
bool Passed = false;
object ZeroValue = 0;
if(o1 != null)
{
if(o1.GetType().IsValueType)
{
Passed = (o1 as System.ValueType).Equals(Convert.ChangeType(ZeroValue, o1.GetType()))
}
else
{
if (o1.GetType() == typeof(String))
{
Passed = o1.Equals(String.Empty);
}
}
}
return Passed;
}

What's wrong with this?
public static bool IsZeroOrEmptyString(object obj)
{
if (obj == null)
return false;
else if (obj.Equals(0) || obj.Equals(""))
return true;
else
return false;
}

Michael, you need to provide a little bit more information here.
strings can be compared to null or string.Empty by using the method
string x = "Some String"
if( string.IsNullOrEmpty(string input) ) { ... }
int, decimals, doubles (and other numeric value-types) can be compared to 0 (zero) with a simple == test
int x = 0;
if(x == 0) { ... }
You can also have nullable value-types also by using the ? operator when you instantiate them. This allows you to set a value type as null.
int? x = null;
if( !x.HasValue ) { }
For any other object, a simple == null test will tell you if its null or not
object o = new object();
if( o != null ) { ... }
Hope that sheds some light on things.

Not quite sure the reasoning behind this, because .Equals is reference equality on reference types, and value equality on value types.
This seems to work, but I doubt its what you want:
static bool IsZeroOrEmpty(object o1)
{
if (o1 == null)
return false;
if (o1.GetType().IsValueType)
{
return (o1 as System.ValueType).Equals(0);
}
else
{
if (o1.GetType() == typeof(String))
{
return o1.Equals(String.Empty);
}
return o1.Equals(0);
}
}

Do you mean null or string.empty, if you're talking about strings?
if (String.IsNullOrEmpty(obj as string)) { ... do something }
Oisin

In the first case by testing if it is null. In the second case by testing if it is string.empty (you answered your own question).
I should add that an object can never be equal to 0. An object variable can have a null reference though (in reality that means the variable has the value of 0; there is no object in this case though)

obj => obj is int && (int)obj == 0 || obj is string && (string)obj == string.Empty

Related

C# Implicit Operator not working with reflection

I am working on a requirement where in I need to check my ASP.NET Model Property for a value 000000.If the value is 000000 then it should be displayed as blank string.
I thought of achieving this using implicit operators.
Here is my model class
public class OrgName
{
private string Value { get; set; }
public static implicit operator string(OrgName org)
{
return org.Value;
}
public static implicit operator OrgName(string value)
{
bool isAllZeros = value.Where(x => char.IsDigit(x)).All(x => x == '0');
if (isAllZeros)
value = string.Empty;
return new OrgName() { Value = value };
}
}
The problem is that we are using reflection to set property values.The above code does not work and the property is always displayed as blank.
Here is the reflection code
var prName = (String.IsNullOrWhiteSpace(parentPrefix) ? objKey : parentPrefix + '.' + objKey);
var pi = modelMap[prName.ToLowerInvariant()].Property;
var value = (collectionProperties.ContainsKey(objKey)) ? collectionProperties[objKey] : pi.GetValue(parentObj);
if (value == null || pi.PropertyType.IsSimpleType())
{
value = (prName == fieldToSet && pi.PropertyType.IsSimpleType())
? (Convert.IsDBNull(valueToSet)) ? null : valueToSet
: createObject(pi.PropertyType);
var type = Nullable.GetUnderlyingType(pi.PropertyType);
//check to see if we need to convert the type when assigning
if (type == typeof(Guid))
value = Guid.Parse(value.ToString());
pi.SetValue(parentObj, type != null ? Convert.ChangeType(value, type) : value);
if (pi.PropertyType != typeof(string) && IsContainerProperty(pi.PropertyType))
continue;
if (pi.PropertyType == typeToReturn)
objToLoad = value;
}
else if (!collectionProperties.ContainsKey(objKey) && IsContainerProperty(pi.PropertyType))
{
var innerType = pi.PropertyType.GetGenericArguments()[0];
var add = pi.PropertyType.GetMethod("Add",
BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public);
if (innerType.IsSimpleType())
{
collectionProperties[objKey] = valueToSet;
add.Invoke(value, new[] { valueToSet });
}
else
{
// Since we can't access the property
var innerObj = createObject(innerType);
collectionProperties[objKey] = innerObj;
add.Invoke(value, new[] { innerObj });
if (innerType == typeToReturn)
objToLoad = innerObj;
continue;
}
}
Can someone help me out with this?
I am also open to other suggestions to achieve this.
Thanks
You could just put the code in the setter?
public class OrgName
{
private string _value;
private string Value
{
get { return _value; }
set
{
bool isAllZeros = value?.All(x => x == '0') ?? false;
if(isAllZeros)
{
_value = string.Empty;
}
else
{
_value = value;
}
}
}
}
This might be an indirect solution to your problem as right now your code has a flaw.
Ex. a0000a0b0 will be detected as isAllZeros
To explain any further what exactly the issue in your code is.
First let's look at this line:
bool isAllZeros = value.Where(x => char.IsDigit(x)).All(x => x == '0');
The first thing you do is taking value and performing a Where on it. The condition for the where to pass is that each value (x) is a digit. Which means that any non-digit characters such as a, b, c will be skipped.
As contrary to what you may have interpreted Where as then it just filters away any values that doesn't match the condition.
This means that values that aren't digits in your case will not pass and thus when the enumeration hits All then it will only enumerate the characters that are digits.
What your code is basically equivalent to in an English speaking is:
Take value
Skip all characters that aren't digits
Check if all digit characters are 0's
What you want your code to actually do is:
Take value
Check if all characters are digits and 0. In this case you actually only have to check if the character is '0'. The char.IsDigit check is redundant.
It could be solved by doing this:
bool isAllZeros = value.All(x => x == '0');
You might want to put in a null check in case value is null though.
bool isAllZeros = value?.All(x => x == '0') ?? false;
In case you aren't using C# 6
bool isAllZeros = string.IsNullOrEmpty(value) ? false : value.All(x => x == '0');

A function to convert null to string

I want to create a function to convert any null value e.g. from a database to an empty string.
I know there are methods such as if value != null ?? value : String.Empty but is there a way to pass null to a method e.g.
public string nullToString(string? value)
{
if(value == null) return empty;
return value
}
But I am not sure on the parameter syntax to do this.
I tried the above but it says not a nullable type.
static string NullToString( object Value )
{
// Value.ToString() allows for Value being DBNull, but will also convert int, double, etc.
return Value == null ? "" : Value.ToString();
// If this is not what you want then this form may suit you better, handles 'Null' and DBNull otherwise tries a straight cast
// which will throw if Value isn't actually a string object.
//return Value == null || Value == DBNull.Value ? "" : (string)Value;
}
When you get a NULL value from a database, the value returned is DBNull.Value on which case, you can simply call .ToString() and it will return ""
Example:
reader["Column"].ToString()
Gets you "" if the value returned is DBNull.Value
If the scenario is not always a database, then I'd go for an Extension method:
public static class Extensions
{
public static string EmptyIfNull(this object value)
{
if (value == null)
return "";
return value.ToString();
}
}
Usage:
string someVar = null;
someVar.EmptyIfNull();
Convert.ToString(object) converts to string. If the object is null, Convert.ToString converts it to an empty string.
Calling .ToString() on an object with a null value throws a System.NullReferenceException.
EDIT:
Two exceptions to the rules:
1) ConvertToString(string) on a null string will always return null.
2) ToString(Nullable<T>) on a null value will return "" .
Code Sample:
// 1) Objects:
object obj = null;
//string valX1 = obj.ToString(); // throws System.NullReferenceException !!!
string val1 = Convert.ToString(obj);
Console.WriteLine(val1 == ""); // True
Console.WriteLine(val1 == null); // False
// 2) Strings
String str = null;
//string valX2 = str.ToString(); // throws System.NullReferenceException !!!
string val2 = Convert.ToString(str);
Console.WriteLine(val2 == ""); // False
Console.WriteLine(val2 == null); // True
// 3) Nullable types:
long? num = null;
string val3 = num.ToString(); // ok, no error
Console.WriteLine(num == null); // True
Console.WriteLine(val3 == ""); // True
Console.WriteLine(val3 == null); // False
val3 = Convert.ToString(num);
Console.WriteLine(num == null); // True
Console.WriteLine(val3 == ""); // True
Console.WriteLine(val3 == null); // False
You can just use the null coalesce operator.
string result = value ?? "";
Its possible to make this even shorter with C# 6:
public string NullToString(string value)
{
return value?.ToString() ?? string.empty;
}
Sometimes I just append an empty string to an object that might be null.
object x = null;
string y = (x + "").ToString();
This will never throw an exception and always return an empty string if null and doesn't require if then logic.
public string nullToString(string value)
{
return value == null ?string.Empty: value;
}
You can use Convert.ToString((object)value). You need to cast your value to an object first, otherwise the conversion will result in a null.
using System;
public class Program
{
public static void Main()
{
string format = " Convert.ToString({0,-20}) == null? {1,-5}, == empty? {2,-5}";
object nullObject = null;
string nullString = null;
string convertedString = Convert.ToString(nullObject);
Console.WriteLine(format, "nullObject", convertedString == null, convertedString == "");
convertedString = Convert.ToString(nullString);
Console.WriteLine(format, "nullString", convertedString == null, convertedString == "");
convertedString = Convert.ToString((object)nullString);
Console.WriteLine(format, "(object)nullString", convertedString == null, convertedString == "");
}
}
Gives:
Convert.ToString(nullObject ) == null? False, == empty? True
Convert.ToString(nullString ) == null? True , == empty? False
Convert.ToString((object)nullString ) == null? False, == empty? True
If you pass a System.DBNull.Value to Convert.ToString() it will be converted to an empty string too.
It is possible to use the "?." (null conditional member access) with the "??" (null-coalescing operator) like this:
public string EmptyIfNull(object value)
{
return value?.ToString() ?? string.Empty;
}
This method can also be written as an extension method for an object:
public static class ObjectExtensions
{
public static string EmptyIfNull(this object value)
{
return value?.ToString() ?? string.Empty;
}
}
And you can write same methods using "=>" (lambda operator):
public string EmptyIfNull(object value)
=> value?.ToString() ?? string.Empty;
you can use ??""
for example:
y=x??""
if x isn't null y=x but if x is null y=""
1. string.Format
You can use string.Format which converts null to empty string
string nullstr = null;
string quotestring = string.Format("{0}", nullstr);
Console.WriteLine(quotestring);//Output- ""
2.string interpolation
or you can use string interpolation. this feature is available in C# 6 and later versions.
InterpolatedExpression produces a result to be formatted. A string representation of the null result is String.Empty.
string nullstr = null;
string quotestring = $"{nullstr}";
Console.WriteLine(quotestring);//Output- ""
public string ToString(this string value)
{
if (value == null)
{
value = string.Empty;
}
else
{
return value.Trim();
}
}
Its an old topic, but there is a "elegant" way to do that...
static string NullToString( object Value )
{
return Value = Value ?? string.Empty;
}
You can try this
public string ToString(this object value)
{
// this will throw an exception if value is null
string val = Convert.ToString (value);
// it can be a space
If (string.IsNullOrEmpty(val.Trim())
return string.Empty:
}
// to avoid not all code paths return a value
return val;
}
you can use null-coalescing-operator C# 8.0 and later
value ??=string.Empty;
??= operators
Assign a nullable string to string.
string? input = "kushal";
string output = input?.ToString() ?? ""
According to the following MSDN page, you need the Convert.ToString method
string x = Convert.ToString((object)value)

Is it possible to modify the boolean value returned when checked if an instance of an object is null?

I was wondering if it is possible to modify the boolean value returned when checked if an instance of an object is null, for example (I know this is wrong and incomplete, just want to give you a reference):
Main:
SuperObject obj = new SuperObject();
if (obj == null) Console.WriteLine("It is null lol!");
SuperObject:
public bool destroyed = false;
public static bool operator ==(SuperObject A, object B)
{
if (A != null && B == null && destroyed == true)
return true;
}
So if the expression (A == null) is checked and A is NOT null but A.destroyed is TRUE, it will return that (A == null) is TRUE.
Basically I want (A == null) to be TRUE when:
A is really null OR A.destroyed = null; The default value for other comparisons.
I would recommend doing this instead:
public static bool IsDestroyed(SuperObject a) {
return (a == null || a.destroyed);
}
Your way would be very confusing to new developers.

Return a variable as soon as it is set to a certain value. Equality overloading

I am overloading the Equality method for value comparison and was wondering if there is a clean way to return false as soon as one of the value comparisons returns false. For example, here is the basic idea:
public class MyClass
{
private int _valOne;
private int _valTwo;
private int _valThree;
public MyClass(int valOne, int valTwo, int valThree)
{
_valOne = valOne;
_valTwo = valTwo;
_valThree = valThree;
}
public override bool Equals(object obj)
{
// If the object is null return false
if (obj == null)
{
return false;
}
// If the object is not of MyClass type return false
MyClass myClass = obj as MyClass;
if (myClass == null)
{
return false;
}
// Now compare all the field values
bool areEqual = false;
areEqual = (this._valOne == myClass._valOne);
areEqual = (this._valTwo == myClass._valTwo);
areEqual = (this._valThree == myClass._valThree);
return areEqual;
}
}
Say the _valOne's do not equal. The most efficient way to compare is to return false as soon as it is known two values are not equal. Something like the following...
// Now compare all the field values
bool areEqual = false;
areEqual = (this._valOne == myClass._valOne);
if (!areEqual)
{
return false;
}
areEqual = (this._valTwo == myClass._valTwo);
if (!areEqual)
{
return false;
}
areEqual = (this._valThree == myClass._valThree);
return areEqual;
So now after the comparison of the _valOnes no more value comparisons are made. This seems very repetitive, clunky, and (most importantly) horrible for readability. I want to know if there is any way this code can be reduced to the same effect in a clean way without the use of the && operator.
You can take advantage of the short-circuiting nature of the logical AND (&&) operator, like this:
return this._valOne == myClass._valOne
&& this._valTwo == myClass._valTwo
&& this._valThree == myClass._valThree;
As soon as any one of the comparisons evaluates to false, the whole condition evaluates to false. If all three are true, the condition returns true.
Use an and condition:
areEqual = (this._valOne == myClass._valOne)
&& (this._valTwo == myClass._valTwo)
&& (this._valThree == myClass._valThree);
&& implements short-circuiting by default.
Another way could be to do this:
if (this._valOne != myClass._valOne)
return false;
if (this._valTwo != myClass._valTwo)
return false;
if (this._valThree != myClass._valThree)
return false;
return true;
A matter of choice I guess. I'd think the && one is more readable..

How can I make my generic comparer (IComparer) handle nulls?

I'm trying to write a generic object comparer for sorting, but I have noticed it does not handle the instance where one of the values it's comparing is null. When an object is null, I want it to treat it the same as the empty string. I've tried setting the null values to String.Empty but then I get an error of "Object must be of type String" when calling CompareTo() on it.
public int Compare(T x, T y)
{
PropertyInfo propertyInfo = typeof(T).GetProperty(sortExpression);
IComparable obj1 = (IComparable)propertyInfo.GetValue(x, null);
IComparable obj2 = (IComparable)propertyInfo.GetValue(y, null);
if (obj1 == null) obj1 = String.Empty; // This doesn't work!
if (obj2 == null) obj2 = String.Empty; // This doesn't work!
if (SortDirection == SortDirection.Ascending)
return obj1.CompareTo(obj2);
else
return obj2.CompareTo(obj1);
}
I'm pretty stuck with this now! Any help would be appreciated.
You cannot treat your T as an empty string unless your T was effectively constrained to being a string. What you should do is have a plan for comparing nulls. Such as
if (obj1 == null && obj2 == null)
return 0;
else if (obj1 == null)
return -1;
else if (obj2 == null)
return 1;
else
return obj1.CompareTo(obj2);
if (SortDirection == SortDirection.Ascending)
return Comparer<T>.Default.Compare(obj1, obj2);
else
return Comparer<T>.Default.Compare(obj2, obj1);
Since T is a generic type, you cannot assign it a String value; you can only assign it a value of type T. If you are only going to use this to compare strings, use String instead of T. Otherwise, add null checking and decide where in order null should fall.
IComparable obj1 = (IComparable)propertyInfo.GetValue(x, null) ?? "";
IComparable obj2 = (IComparable)propertyInfo.GetValue(y, null) ?? "";
This basically means that obj1 will now be the value of propertyInfo.GetValue(x, null) or, if that happens to be null, obj1 will be "".
Or if the problem is that the GetValue crashes on null you could do something like:
IComparable obj1 = "";
try { obj1 = (IComparable)propertyInfo.GetValue(x, null); } catch {}

Categories

Resources