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







All Articles