Typically Typed Expression
The code below shows the error:
Property 'Int32 Key' is undefined for type 'ConsoleApplication1.IKeyed`1 [TKey]'when expression e is created, but fine when function func f can anyone explain why and if there is a way to fix this?
Module Module1
Sub Main()
Dim g = New keyedThingGetter(Of KeyedThing, Integer)
Dim thing = g.getThing()
End Sub
End Module
Public Class keyedThingGetter(Of Tthing As IKeyed(Of TKey), TKey)
Public Function getThing() As Tthing
Dim f As Func(Of Tthing, Boolean)
f = Function(thing) thing.Key.Equals(1)
Dim e As Expressions.Expression(Of Func(Of Tthing, Boolean))
e = Function(thing) thing.Key.Equals(1)
Return Nothing
End Function
End Class
Public Interface IKeyed(Of TKey)
ReadOnly Property Key() As TKey
End Interface
Public Class KeyedThing
Implements IKeyed(Of Integer)
Public ReadOnly Property Key() As Integer Implements IKeyed(Of Integer).Key
Get
Return 1
End Get
End Property
End Class
0
source to share
1 answer
The workaround is at the bottom
It is very strange. I'm still looking at it, but this "mostly equivalent" C # works fine:
using System;
using System.Linq.Expressions;
interface IKeyed<TKey>
{
TKey Key { get; }
}
class KeyedThing : IKeyed<int>
{
public int Key { get { return 1; } }
}
class KeyedThingGetter<TThing, TKey> where TThing : IKeyed<TKey>
{
public void GetThing()
{
Func<TThing, bool> f = thing => thing.Key.Equals(1);
Expression<Func<TThing, bool>> e = thing => thing.Key.Equals(1);
}
}
class Test
{
static void Main()
{
var g = new KeyedThingGetter<KeyedThing, int>();
g.GetThing();
}
}
EDIT: There is an interesting difference between the generated expression trees. Here's a VB expression (decompiled in C # with Reflector):
Expression<Func<Tthing, bool>> expression = Expression
.Lambda<Func<Tthing, bool>> (Expression.Call(Expression.Convert
(Expression.Property(Expression.Convert(expression2 =
Expression.Parameter(typeof(Tthing), "thing"), typeof(IKeyed<>)),
(MethodInfo) methodof(IKeyed<TKey>.get_Key, IKeyed<TKey>)), typeof(object)),
(MethodInfo) methodof(object.Equals), new Expression[] {
Expression.Convert(Expression.Constant(1, typeof(int)), typeof(object)) }), new
ParameterExpression[] { expression2 });
Here's the C # version:
Expression<Func<TThing, bool>> expression = Expression
.Lambda<Func<TThing, bool>> (Expression.Call(Expression.Convert
(Expression.Property(Expression.Convert(expression2 =
Expression.Parameter(typeof(TThing), "thing"), typeof(IKeyed<TKey>)),
(MethodInfo) methodof(IKeyed<TKey>.get_Key, IKeyed<TKey>)), typeof(object)),
(MethodInfo) methodof(object.Equals), new Expression[] {
Expression.Convert(Expression.Constant(1, typeof(int)), typeof(object)) }), new
ParameterExpression[] { expression2 });
The difference lies in the fourth line - the type of the parameter. In C # it is typeof(IKeyed<TKey>)
, whereas in VB it is typeof(IKeyed<>)
.
Possibly a bug in the VB compiler? Not sure yet. Hope Marc G will call back soon as the resident expression tree ...
EDIT: Given the difference, I figured out how to fix this. Or change it to:
Dim e as Expressions.Expression(Of Func(Of Tthing, Boolean))
e = Function(thing as IKeyed(Of TKey)) thing.Key.Equals(1))
or
Dim e as Expressions.Expression(Of Func(Of IKeyed(Of TKey), Boolean))
e = Function(thing) thing.Key.Equals(1))
+1
source to share