Say I have a function such as:
public TProperty Foo<TClass, TProperty>(TClass instance, Expression<Func<TClass, TProperty>> expression)
{
...
}
But then I realize it should only be used for value types, so I add a constraint
public TProperty Foo<TClass, TProperty>(TClass instance, Expression<Func<TClass, TProperty>> expression)
where TProperty : struct
{
...
}
But I then discover that this won't let me pass in expressions that take a nullable TProperty. The only way I can see to handle this is to do the following:
public TProperty Foo<TClass, TProperty>(TClass instance, Expression<Func<TClass, TProperty?>> expression)
where TProperty : struct
{
...
}
But now I am forced to maintain two methods that do exactly the same thing, except that one deals with nullables, and one doesn't.
Further more I can't extract them into a common method, because even though a conversion exists from T to T?, there is apparently no conversion from
Expres开发者_开发问答sion<Func<T1, T2>>
to
Expression<Func<T1, T2?>>
If the body of these methods is complicated, I really don't want to have to maintain two separate versions of them, especially when in fact it is a whole family of functions.
Is there any way to avoid this code duplication and still have the compiler enforce that the expression must end in either a value type or a nullable?
(I am currently using C# 3.5, but am open to more recent versions if they provide a clean solution.)
Depending on what you're doing with the expression, you could make both overloads call a private overlaod that takes a (untyped) LambdaExpression
.
In cases like these it can be still OK to use method overloading provided the logic is refactored to a private method.
I think you can restrict it on where TProperty : Nullable<TProperty>
though I have not checked this
In .NET 4, Func<P, Q>
is actually covariant on Q
. So this idea might work, but alas, Nullable<T>
is not related to T
. (Here is an example.), so Func<P, Q>
has no chance to be used where Func<P, Q?>
is expected.
精彩评论