【问题标题】:Generically typed expression weirdness泛型表达怪异
【发布时间】:2008-11-11 16:08:35
【问题描述】:

下面的代码报错:

在创建表达式 e 时没有为类型“ConsoleApplication1.IKeyed`1[TKey]”定义属性“Int32 Key”,但在创建 func f 时没问题,谁能解释为什么以及是否存在有办法解决吗?
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

【问题讨论】:

    标签: vb.net linq generics


    【解决方案1】:

    解决方法在底部

    这很奇怪。我仍在研究它,但这个“大部分等效”的 C# 工作正常:

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

    编辑:创建的表达式树之间有一个有趣的区别。这是VB表达式(使用Reflector反编译为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<>)),
    (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 });
    

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

    区别在于第四行——参数的类型。在 C# 中为typeof(IKeyed&lt;TKey&gt;),而在 VB 中为typeof(IKeyed&lt;&gt;)

    可能是 VB 编译器中的错误?尚未确定。希望 Marc G 能尽快加入,作为常驻表达式树专家...

    编辑:鉴于差异,我想出了如何解决它。将其更改为:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多