views:

52

answers:

2

I want a single generic class that can accept either reference or value types, and only perform an action based on an equality test. consider the following:

public class Property<TProp>
  where TProp : struct, IEquatable<TProp>
{
   public TProp Value;

   public void SetValue(ObservableObject owner, TProp value)
   {
      if (!Value.Equals(value))     // cannot use != on struct constrained TProp
      {
          // ... set the property
      }
   }
}

public class ByRefProperty<TProp>
  where TProp : class   // Dont want to require IEquatable<> on reference type TProp
{
   public TProp Value;

   public void SetValue(ObservableObject owner, TProp value)
   {
      if (Value != value)           
      {
          // ... set the property
      }
   }
}

I'm having to use generic constraints and two classes to be able to test value type equality vs reference type equality. Is there any way around this so that I end up with just one class?

I don't particularly want a solution that involves boxing value types, using reflection, or run-time IL generation. Is there a simple solution that I've missed here?

+7  A: 

The best way do to this is generally EqualityComparer<T>.Default:

public void SetValue(ObservableObject owner, TProp value)
{
   if (!EqualityComparer<TProp>.Default.Equals(Value, value))
   {
       // ... set the property
   }
}

Note that this even handles null values for you in the logical way (null is equal to null but nothing else).

Jon Skeet
Will this use any custom Equals logic defined in the implemenation of `IEquatable<T>`?
Justin Niessner
@Justin, yes it does, if the type implements it.
Jon Hanna
@Jon - Learn something new every day...again.
Justin Niessner
A: 

You can check if the type is a value type in the static constructor:

private static readonly isValueType;

static Property()
{
    isValueType = typeof(TProp).IsValueType;
}
Steven