使用表达式的 C# 通用静态调用失败

发布于 2024-10-19 11:20:14 字数 1046 浏览 1 评论 0原文

我试图通过反映通用方法 Find 来获取 SubSonic IActiveRecord,如下所示:(

请忽略定位 MethodInfo 时的初稿丑陋之处)

private T GetSavedRecord<T>(string tag) where T : IActiveRecord, ITagged 
{
  //Some internal caching stuff

  ...

  MethodInfo info = typeof(T).GetMethods(BindingFlags.Static | BindingFlags.Public)
                             .FirstOrDefault(m => m.Name == "Find" && m.GetParameters().Count() == 1);

  Expression<Func<T, bool>> predicate = e => e.Tag == tag;                            

  T record = ((IList<T>)info.Invoke(null, new object[] { predicate })).FirstOrDefault(); 

  return //cached record
}

ITagged 简单地定义了

  string Tag { get; set; }

当我调用指向 Find 函数的 MemberInfo 时,我得到一个 System抛出 .NotSupportedException,并显示以下消息:

“不支持成员‘标签’”

但是,我能够使用相同的谓词在任何实际的 IActiveRecord 实现上调用静态 Find 方法。

(对于那些精通 SubSonic 的人,我修改了 .tt 模板以在所有生成的类上包含 ITagged 接口)

我不认为这个问题与 SubSonic 特别相关,但我想我会提到它,以防万一。

I am trying to fetch a SubSonic IActiveRecord by reflecting on the generic method Find, as follows:

(please ignore the first draft ugliness in locating the MethodInfo)

private T GetSavedRecord<T>(string tag) where T : IActiveRecord, ITagged 
{
  //Some internal caching stuff

  ...

  MethodInfo info = typeof(T).GetMethods(BindingFlags.Static | BindingFlags.Public)
                             .FirstOrDefault(m => m.Name == "Find" && m.GetParameters().Count() == 1);

  Expression<Func<T, bool>> predicate = e => e.Tag == tag;                            

  T record = ((IList<T>)info.Invoke(null, new object[] { predicate })).FirstOrDefault(); 

  return //cached record
}

ITagged simply defines

  string Tag { get; set; }

When I Invoke the MemberInfo pointing to the Find function, I am getting a System.NotSupportedException being thrown, with the following message:

"The member 'Tag' is not supported"

I am, however, able to call the static Find method on any of the actual IActiveRecord implementations with the same predicate.

(for those savvy with subsonic, I have modified the .tt template to include the ITagged interface on all generated classes)

I don't think this issue is particularly relevant to SubSonic, but thought I'd mention it, just in case.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

ˇ宁静的妩媚 2024-10-26 11:20:14

如果我理解正确的话,您基本上是在尝试针对提供程序 (SubSonic) 创建 LINQ 查询,该提供程序将尝试解析 LINQ 表达式以生成针对基础数据存储的查询。问题是 ITagged.Tag 在 SubSonic 的世界中不存在,因此无法对其进行查询。您需要使表达式树基于实际的 T.Tag 属性。

沿着这些思路的东西应该有效:

var tagMember = typeof(T).GetProperty("Tag");
var eParam = Expression.Parameter(typeof(T), "e");
var predicate = 
    Expression.Lambda<Func<T, bool>>(
        Expression.Equal(
            Expression.Property(eParam, tagMember), 
            Expression.Constant(tag)
        ),
        eParam);

If I'm understanding correctly, you're basically trying to create a LINQ query against a provider (SubSonic) that will try to parse out the LINQ expressions to produce a query against an underlying data store. The problem is that ITagged.Tag does not exist in SubSonic's world, so it cannot query against it. You're going to need to make your expression tree be based on the actual T.Tag property instead.

Something along these lines should work:

var tagMember = typeof(T).GetProperty("Tag");
var eParam = Expression.Parameter(typeof(T), "e");
var predicate = 
    Expression.Lambda<Func<T, bool>>(
        Expression.Equal(
            Expression.Property(eParam, tagMember), 
            Expression.Constant(tag)
        ),
        eParam);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文