4

,I have one class in which I have three properties now what I want to do, if in the object if any one of null or empty then I want to remove it from the object below is my code.

public class TestClass
{
    public string Name { get; set; }
    public int ID { get; set; }
    public DateTime? DateTime { get; set; }
    public string Address { get; set; }
}
       TestClass t=new TestClass();
        t.Address="address";
        t.ID=132;
        t.Name=string.Empty;
        t.DateTime=null;

Now here I want the object of TestClass but in that Name and DateTime property should not be their in the object, is it possible? Please help me

Dhaval Patel
  • 7,471
  • 6
  • 37
  • 70

5 Answers5

7

I was bored and got this in LINQPad

void Main()
{
    TestClass t=new TestClass();
    t.Address="address";
    t.ID=132;
    t.Name=string.Empty;
    t.DateTime=null;

    t.Dump();
    var ret = t.FixMeUp();
    ((object)ret).Dump();
}

public static class ReClasser
{
    public static dynamic FixMeUp<T>(this T fixMe)
    {
        var t = fixMe.GetType();
        var returnClass = new ExpandoObject() as IDictionary<string, object>;
        foreach(var pr in t.GetProperties())
        {
            var val = pr.GetValue(fixMe);
            if(val is string && string.IsNullOrWhiteSpace(val.ToString()))
            {
            }
            else if(val == null)
            {
            }
            else
            {
                returnClass.Add(pr.Name, val);
            }
        }
        return returnClass;
    }
}

public class TestClass
{
    public string Name { get; set; }
    public int ID { get; set; }
    public DateTime? DateTime { get; set; }
    public string Address { get; set; }
}
NoLifeKing
  • 1,909
  • 13
  • 27
  • It's an extension in a great software called [LINQPad](http://www.linqpad.net/) :) I use it everyday to create small utility-scripts that can help me through the day. – NoLifeKing Aug 01 '13 at 08:01
  • 1
    So I have to add reference for it? – Dhaval Patel Aug 01 '13 at 08:06
  • Nope, just remove the `.Dump()` rows and you should be able to use `ret` to put in your schemaless DB. Although, if your DB goes on the name on the class, this won't work, since it returns a totally different class. – NoLifeKing Aug 01 '13 at 08:07
  • 1
    Note that the fixed object is no longer an instance of `TestClass`, so you can't for example return it from any method that returns `TestClass`. – Ilmo Euro Aug 01 '13 at 08:08
  • `.Dump()` is as I said, an extension in LINQPad, that is used mostly for debugging, almost like `Console.WriteLine` – NoLifeKing Aug 01 '13 at 08:08
  • No no my database is not dependent any class it's a dynamic – Dhaval Patel Aug 01 '13 at 08:09
  • Then it should work, but I think you should listen to Jon Skeet. My solution is just dirty. – NoLifeKing Aug 01 '13 at 08:10
  • @IlmoEuro Actually, if he is using MongoDB, he _should_ be able to return it as a `TestClass`, since it skips the fields that's missing (replacing them with `NULL`-values) – NoLifeKing Aug 01 '13 at 08:12
  • How do you import ExpandoObject into LinqPad? – Demodave May 10 '17 at 21:24
  • @Demodave By referencing `System.Dynamic` – NoLifeKing May 11 '17 at 06:04
6

There's no such concept as removing a property from an individual object. The type decided which properties are present - not individual objects.

In particular, it will always be valid to have a method like this:

public void ShowDateTime(TestClass t)
{
    Console.WriteLine(t.DateTme);
}

That code has no way of knowing whether you've wanted to "remove" the DateTime property from the object that t refers to. If the value is null, it will just get that value - that's fine. But you can't remove the property itself.

If you're listing the properties of an object somewhere, you should do the filtering there, instead.

EDIT: Okay, no you've given us some context:

ok I am using Schemaless database so null and empty value also store space in database that's the reason

So in the code you're using which populates that database, just don't set any fields which corresponds to properties with a null value. That's purely a database population concern - not a matter for the object itself.

(I'd also argue that you should consider how much space you'll really save by doing this. Do you really care that much?)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Yes because per day in my database there is 2,50,000 record inserted and I have to retrieve that and Perform Some calculation on it so I have to take care of this concern. – Dhaval Patel Aug 01 '13 at 07:24
  • 3
    @DhavalPatel: Have you actually measured how much difference that makes in terms of data and retrieval time? I suspect it's vanishingly small. – Jon Skeet Aug 01 '13 at 07:37
  • :in my database there is one trigger which can moved one table data from another when it's reached limit of 85,00,000 so after more then 30 days in table there should be around 60,00,00 data and I am using silverlight application which take time to load data .. – Dhaval Patel Aug 01 '13 at 08:05
  • 8.5 million *whats*? Bytes? Rows? Megabytes? Regardless of that, you still haven't answered my question about whether you've *measured* the difference. I strongly suspect you're optimizing prematurely, unless a large proportion of the fields are missing for a large proportion of the rows. – Jon Skeet Aug 01 '13 at 08:08
  • 8.5 million Rows. ya I have measured it. – Dhaval Patel Aug 01 '13 at 08:16
3

Hereby a 'slightly' more clear and shorter version of the accepted answer.

        /// <returns>A dynamic object with only the filled properties of an object</returns>
        public static object ConvertToObjectWithoutPropertiesWithNullValues<T>(this T objectToTransform)
        {
            var type = objectToTransform.GetType();
            var returnClass = new ExpandoObject() as IDictionary<string, object>;
            foreach (var propertyInfo in type.GetProperties())
            {
                var value = propertyInfo.GetValue(objectToTransform);
                var valueIsNotAString = !(value is string && !string.IsNullOrWhiteSpace(value.ToString()));
                if (valueIsNotAString && value != null)
                {
                    returnClass.Add(propertyInfo.Name, value);
                }
            }
            return returnClass;
        }
Nick N.
  • 12,902
  • 7
  • 57
  • 75
  • Best Answer. However you can remove `valueIsNotAString` as there would be another type of objects too. We can put this condition to check as a boolean in arguments to make it more generic. – vibs2006 Sep 01 '20 at 13:58
2

You could take advantage of the dynamic type:

class Program
{
    static void Main(string[] args)
    {
        List<dynamic> list = new List<dynamic>();
        dynamic
            t1 = new ExpandoObject(),
            t2 = new ExpandoObject();

        t1.Address = "address1";
        t1.ID = 132;

        t2.Address = "address2";
        t2.ID = 133;
        t2.Name = "someName";
        t2.DateTime = DateTime.Now;

        list.AddRange(new[] { t1, t2 });

        // later in your code
        list.Select((obj, index) =>
            new { index, obj }).ToList().ForEach(item =>
        {
            Console.WriteLine("Object #{0}", item.index);
            ((IDictionary<string, object>)item.obj).ToList()
                .ForEach(i =>
                {
                    Console.WriteLine("Property: {0} Value: {1}",
                        i.Key, i.Value);
                });
            Console.WriteLine();
        });

        // or maybe generate JSON
        var s = JsonSerializer.Create();
        var sb=new StringBuilder();
        var w=new StringWriter(sb);
        var items = list.Select(item =>
        {
            sb.Clear();
            s.Serialize(w, item);
            return sb.ToString();
        });

        items.ToList().ForEach(json =>
        {
            Console.WriteLine(json);
        });
    }
}
Alex Filipovici
  • 31,789
  • 6
  • 54
  • 78
1

May be interfaces will be handy:

public interface IAdressAndId
    {
        int ID { get; set; }
        string Address { get; set; }
    }
    public interface INameAndDate
    {
        string Name { get; set; }
        DateTime? DateTime { get; set; }
    }
    public class TestClass : IAdressAndId, INameAndDate
{
    public string Name { get; set; }
    public int ID { get; set; }
    public DateTime? DateTime { get; set; }
    public string Address { get; set; }
}

Creating object:

IAdressAndId t = new TestClass()
            {
                Address = "address",
                ID = 132,
                Name = string.Empty,
                DateTime = null
            };

Also u can put your interfaces in separate namespace and make your class declaration as internal. After that create some public factories which will create the instances of your classes.

sickUnit
  • 319
  • 2
  • 5