Thursday, August 13, 2009

Problems with conversion operator in abstract classes

Sad truth - no way to implement operator convertion in abstract class like this:
public abstract class DoubleValueBase
{
protected DoubleValueBase(double value)
{
AssertThatValueIsWithinRange(value);
this.Value = value;
}
public double Value { get; private set; }
public static implicit operator DoubleValueBase(double value)
{
return (DoubleValueBase)Activator.CreateInstance(??);
}
public static explicit operator double(DoubleValueBase value)
{
return value.Value;
}
protected abstract void AssertThatValueIsWithinRange(double value);
}
So it isn't possible to derive Power class from DoubleValueBase and write

Power power = 5.3;

unless you create implicit convertion operator in Power class. Now imagine, that you need to have 20 classes derived from DoubleValueBase.

P.S. If anybody have an idea if it is possible to do with languages like Boo or Nemerle give me a call please.

Tuesday, August 4, 2009

ValidateLambdaArgs and problems with casting linq Expression

Was stuck with a problem while implementing strogly typed mappings via linq expressions for a while. The problem was with passing Expression into method with reflection.

typeof(SomeClassRepository)
.GetMethod("LoadBy")
.Invoke(repository, new object[] { lambdaExpression, valueToMatch });
Actual signature of LoadBy looks like this:
public SomeClass LoadBy(Expression<Func<SomeClass, object>> expression, string value)
I want to build expression like x=>x.SomeProperty and pass it to LoadBy via reflection. The problem however arise its head when trying to pass value types when building expression:

var intPropertyName = "IntProperty";

var type = typeof(SomeClass);
var parameterExpression = Expression.Parameter(type, "x");
var memberExpression = Expression.Property(parameterExpression, intPropertyName);
var delegateType = typeof(Func<,>).MakeGenericType(new Type[] { type, typeof(object) });

var lambdaExpression = Expression.Lambda(delegateType,memberExpression, new[] { parameterExpression });

Here's definition of SomeClass:
public class SomeClass
{
public int IntProperty { get; set; }
}
Building such lambda expression raises System.ArgumentException in System.Linq.Expressions.Expression.ValidateLambdaArgs. Exception will say that you cannot use System.Int32 for return type System.Object.

To avoid this I found no way other than to use more reflection stuff and make a hack. Building lambda expression with following code instead of Expression.Lambda(...) fixed the problem:

var onlys = new ReadOnlyCollection<ParameterExpression>(new List<ParameterExpression> { parameterExpression });
var specificType = typeof(Expression<>).MakeGenericType(new System.Type[] { delegateType });
var lambdaExpression = Activator.CreateInstance(specificType,
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new object[] { memberExpression, onlys },
null);