views:

858

answers:

1

I'm trying to add a constraint to a generic method so it checks for ValueTypes, Strings or Nullable value types.

The problem is that:

  • value types are struts
  • strings are immutable reference types
  • nullable are value types but won't be accepted in a "where S : struct" type constraint.

So does anybody know if there's a way I can accept these and only these types in a generic constraint?

The problem is I'm trying to accept an Expression<Func<T, S> parameter that will represent a property of these types for a given object.

The functionality would be something like the following (note the code doesn't make any sense and is just something quick to get an idea of what I'm looking for):

public class Person
{
   public string Name {get; set;}
   public DateTime? DOB {get; set;}
   public int NumberOfChildren {get; set;}
   public Car CurrentCar {get; set;}
}

---

internal void MyGenericMethod<T, S>(T myObject, Expression<Func<T, S> property){...}

Person myPerson = new Person();
MyGenericMethod(myPerson, p => p.Name); //S would be a string
MyGenericMethod(myPerson, p => p.DOB); //S would be a DateTime? 
MyGenericMethod(myPerson, p => p.NumberOfChildren); //S would be a struct

The three calls above should all be accepted, but not the following:

MyGenericMethod(myPerson, p => p.CurrentCar); //S would be a class and shouldn't compile

Thanks in advance

UPDATE: Thanks Anton and Marc. MyGenericMethod has 4 different signatures accepting extra parameters, that's why I don't like the idea of creating 3 different (struct, nullable, string) for each of the existing 4... that would be a nightmare to maintain!

+4  A: 

The only thing I can come up with is a set of three functions (sans Expression<> stuff):

MyGenericFunction<T>(T t)
    where T : struct

MyGenericFunction<T>(T? t)
    where T : struct

MyGenericFunction(string s)

UPDATE Given that there are various overloads of a method, I can suggest:

class Holder
{
    private object value;

    public Holder(object value)
    {
        this.value = value;
    }

    public static implicit operator Holder(DateTime dt)
    {
        return new Holder(dt);
    }

    public static implicit operator Holder(string s)
    {
        return new Holder(s);
    }

    // Implicit conversion operators from primitive types
}

Thus your method becomes

MyGenericMethod(Holder h);

Still very cumbersome, but nevertheless it might work out.

Anton Gogolev