开发者

Convert Nulls to Empty String in an object

开发者_如何学运维What is the easiest way to take an objects and convert any of its values from null to string.empty ?

I was thinking about a routine that I can pass in any object, but I am not sure how to loop through all the values.


When your object exposes it's values via properties you can write something like:

string Value { get { return m_Value ?? string.Empty; } }

Another solution is to use reflection. This code will check properties of type string:

var myObject = new MyObject();
foreach( var propertyInfo in myObject.GetType().GetProperties() )
{
    if(propertyInfo.PropertyType == typeof(string))
    {
        if( propertyInfo.GetValue( myObject, null ) == null )
        {
            propertyInfo.SetValue( myObject, string.Empty, null );
        }
    }
}


Using reflection, you could something similar to :

public static class Extensions
{
    public static void Awesome<T>(this T myObject) where T : class
    {
        PropertyInfo[] properties = typeof(T).GetProperties();
        foreach(var info in properties)
        {
            // if a string and null, set to String.Empty
            if(info.PropertyType == typeof(string) && 
               info.GetValue(myObject, null) == null)
            {
                info.SetValue(myObject, String.Empty, null);
            }
        }
    }
}


Presumably, you have a report or a form somewhere showing "null" all over the place, instead of a nice, pleasant "".

It's best to leave the nulls as they are, and modify your display code wherever appropriate. Thus, a line like this:

label1.Text = someObject.ToString();

should become:

if (someObject == null)
{
    label1.Text = ""; // or String.Empty, if you're one of *those* people
}
else
{
    label1.Text = someObject.ToString();
}

and you can functionalize it as necessary:

public void DisplayObject(Label label, Object someObject)
{
    if (someObject == null)
    {
        label.Text = ""; // or String.Empty, if you're one of *those* people
    }
    else
    {
        label.Text = someObject.ToString();
    }
}


You could use reflection. Here's an example with one level of nesting:

class Foo
{
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public string Prop3 { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var foo = new Foo
        {
            Prop1 = (string)null,
            Prop2 = (string)null,
            Prop3 = (string)null,
        };

        var props = typeof(Foo).GetProperties()
            .Where(x => x.PropertyType == typeof(string));
        foreach (var p in props)
        {
            p.SetValue(foo, string.Empty, null);
        }
    }
}


You can do that via reflection without too much trouble, and I am sure that by the time I post this there will be answers that tell you exactly how to do that.

But I personally don't like the reflection option.

I prefer to maintain object invariants for all of the object's members through a variety of means. For string members, the invariant is often that it not be null, and sometimes there are maximum length requirements as well (for storage in a database, for example). Other members have other sorts of invariants.

The first step is to create a method that checks all the invariants that you define for the object.

[Conditional("DEBUG")]
private void CheckObjectInvariant()
{
    Debug.Assert(name != null);
    Debug.Assert(name.Length <= nameMaxLength);
    ...
}

Then you call this after any method that manipulates the object in any way. Since it is decorated with the ConditionalAttribute, none of these calls will appear in the release version of the application.

Then you just have to make sure that none of the code allows any violations of these invariants. This means that the string fields need to have either initializers in their declarations or they need to be set in all the constructors for the object.

A special problem, and the one that probably motivated this question, is what to do about automatic properties.

public string Name { get; set; }

Obviously, this can be set to null at any time, and there's nothing you can do about that.

There are two options with regard to automatic properties. First, you can just not use them at all. This avoids the problem entirely. Second, you can just allow any possible string value. That is, any code that uses that property has to expect nulls, 10 mb strings or anything in between.

Even if you go with the reflection option to remove nulls, you still have to know when to call the magic-null-removal method on the object to avoid NullReferenceExceptions, so you haven't really bought anything that way.


+1 to Tanascius's answer. I used this answer but tweaked it a bit.

First I only grab the properties that are strings, so it doesn't loop through all my properties. Secondly, I placed in it my BaseEntity class that all my entities inherit from, which makes it global, so I don't have to put it on all my Entities.

public class BaseEntity
{
    public int Id { get; set; }

    public BaseEntity()
    {
        var stringProperties = this.GetType().GetProperties().Where(x => x.PropertyType == typeof(string));

        foreach (var property in stringProperties)
        {
            if (property.GetValue(this, null) == null)
            {
                property.SetValue(this, string.Empty, null);
            }
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜