2008-11-11 6 views
0

Le code ci-dessous donne une erreur: Étrangeté d'expression typée générique

Property 'Int32 Key' is not defined for type 'ConsoleApplication1.IKeyed`1[TKey]'
lorsque l'expression e est créée mais est correcte lors de la création de func f, quelqu'un peut-il expliquer pourquoi et s'il y a moyen de résoudre ce problème?

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 

Répondre

1

Solution est au fond

C'est très étrange. Je suis toujours en elle, mais « la plupart du temps équivalent » C# fonctionne très bien:

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: Il y a une différence intéressante entre les arbres d'expression créés. Voici l'expression VB (décompilé à C# avec réflecteur):

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 }); 

est ici la version C#:

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 }); 

La différence est dans le fourthline - le type du paramètre. Dans le C#, c'est typeof(IKeyed<TKey>) alors que dans le VB c'est typeof(IKeyed<>).

Un bogue dans le compilateur VB peut-être? Pas encore sûr. Espérons que Marc G interviendra bientôt, en tant qu'expert résident de l'arbre d'expression ...

EDIT: Étant donné la différence, j'ai trouvé comment y remédier. Modifiez à:

Dim e as Expressions.Expression(Of Func(Of Tthing, Boolean)) 
e = Function(thing as IKeyed(Of TKey)) thing.Key.Equals(1)) 

ou

Dim e as Expressions.Expression(Of Func(Of IKeyed(Of TKey), Boolean)) 
e = Function(thing) thing.Key.Equals(1)) 
Questions connexes