Nodoid
Nodoid

Reputation: 1561

Finding if all properties within a class are the same

I have a simple class that contains 4 double properties like this

 public MyClass
 {
     public MyClass(double all = 0)
     {
         Top = Bottom = Left = Right = all;
     }
     public MyClass(double lr = 0, double tb = 0)
     {
         Top = Bottom = tb;
         Left = Right = lr;
     }
     public MyClass(double l = 0, double r = 0, double t = 0, double b = 0)
     {
         Top = t;Bottom = b;Left = l;Right = r;
     }

     public double Top {get; private set;}
     public double Bottom {get; private set;}
     public double Left {get; private set;}
     public double Right {get; private set;}
}

Is there a simple way to check if all the properties have the same value? I'd rather not use if (Top == Bottom) && (Top == Left) ... as it's somewhat messy IMHO. Can it be done in LINQ?

Upvotes: 1

Views: 182

Answers (5)

MakePeaceGreatAgain
MakePeaceGreatAgain

Reputation: 37000

To underline what @CodeCaster already mentioned concerning the messyness the following would be the appropriate code for that:

var properties = typeof(MyClass).GetProperties();
var first = proerties[0].GetValue(myInstance, null);
if (properties.Select(x => x.GetValue(myInstance, null)).All(x => x.Equals(first)) 
{ 
    /* ... */ 
}

This checks for all properties within your type MyClass by reflection. However everything is better than this approach, only added it for completeness. If you want it some stable you´d at least have to also prove if the class actually has any properties.

This only applies for non-indexed properties. If your property is indexed you´ll also have to prove for every element also which gets much dirtier.

Now compare this to the really nice and short Top == Bottom && Left == Top && Right == Left from @Yuval.

Upvotes: 3

Dominic Cotton
Dominic Cotton

Reputation: 819

bool b = (Top == (new double[] { Top, Bottom, Left, Right }).Average());

This could be an alternative workaround?

Dom

Upvotes: -1

CSharpie
CSharpie

Reputation: 9467

Im really a big fan of writing a Method for cases like this, since it is reusable and has a name that tells whats happening here.

public static bool AllEqual<T>(T frist, params T[] values)
{
    return values.All(v => Equal(first,v));
}

And then use it like this:

ObjectHelper.AllEqual(Top, Bottom, Left, Right);

Upvotes: 2

CodeCaster
CodeCaster

Reputation: 151586

LINQ works on collections. You don't have a collection, you have four separate properties.

Anything you're going to do to force this into LINQ is only going to make it more messy.

Just use plain old C#:

public bool AllPositionsEqual
{
    get
    {
        return Top == Bottom 
            && Left == Right
            && Left == Top;
    }
}

This is clear to you now, and clear to another reader when they read it, and clear to you when you read it in a few months.

If you're going to stuff the properties in a collection just to be able to call a LINQ method on it in order to determine they are all the same, you are breaking the "principle of least astonishment". The reader of that code will go "WTF".

If, instead, you want to be able to do this on an arbitrary class (which would also be a really confusing requirement), you can do it as such:

  • Get all properties using reflection
  • Get all properties' values for this instance in a collection
  • On this collection, call Distinct().

Then you'll have a legitimate use case for LINQ. Right now, you haven't.

Upvotes: 5

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149538

You can insert them into a HashSet<double>:

var doubles = new HashSet<double> { Top, Left, Right, Bottom };
if (doubles.Count == 1)
{
    // Do stuff
}

Or use Enumerable.Distinct:

var doubles = new[] { Top, Bottom, Left, Right };
if (doubles.Distinct().Count() == 1)
{
    // Do stuff
}

But perhaps the most simple approach is to create a method (or a property, if you fancy that):

public class MyClass
{
    public bool AreAllPropertiesSame()
    {
        return Top == Bottom && Left == Top && Right == Left;
    }
}

Note any use of LINQ will incur more overhead then doing a simply if check on 4 properties. I would definitely go with a simple property or method approach which is clear and concise. Don't defer to LINQ because you can, use it because it is the best tool for the job, where clearly here it isn't.

Upvotes: 5

Related Questions