【问题标题】:Passing a predicate that was passed in as a parameter传递作为参数传入的谓词
【发布时间】:2015-06-10 03:20:45
【问题描述】:

我在将谓词传递给另一个函数时遇到问题。该谓词将作为试图调用第二个函数的参数传入。下面是代码sn-p。

public IEnumerable<ViewModel> BuildModel<TPart, TRecord>(Expression<Func<TRecord, bool>> predicate) 
                where TPart : ContentPart<TRecord>
                where TRecord : ContentPartRecord
            {
                IEnumerable<ReportPart> items = GetList<ReportPart, ReportRecord>(predicate);

这个问题是谓词参数,在调用GetList() 时一直出错,说调用有一些无效的参数。获取列表调用是:

 public IEnumerable<TPart> GetList<TPart, TRecord>(Expression<Func<TRecord, bool>> predicate)
            where TPart : ContentPart<TRecord>
            where TRecord : ContentPartRecord

我一直在尝试以多种不同的方式更改参数以使其正常工作,但我没有取得任何成功。也许我不明白为什么编译器认为“谓词”与GetList() 所期望的不同。

编辑:更多信息

ReportPart : ContentPart<ReportRecord>

ReportRecord : ContentPartRecord

ContentPart 和 ContentPartRecord 都是基类

BuildModels 的调用者

List<ReportViewModel> model = _service.BuildReports<ReportPart, ReportRecord>(x => x.Id == 1).ToList();

构建模型

public IEnumerable<ReportViewModel> BuildReports<TPart, TRecord>(System.Linq.Expressions.Expression<Func<TRecord, bool>> predicate)
            where TPart : ContentPart<TRecord>
            where TRecord : ContentPartRecord
{
            List<ReportViewModel> model = new List<ReportViewModel>();
            IEnumerable<ReportPart> reportParts = GetList<ReportPart, ReportRecord>(predicate);
            //do some stuff with reportParts
            return model;
    }
}

获取列表

 public IEnumerable<TPart> GetList<TPart, TRecord>(System.Linq.Expressions.Expression<Func<TRecord, bool>> filter)
            where TPart : ContentPart<TRecord>
            where TRecord : ContentPartRecord
        {
            return filter == null ?
                Services.ContentManager.Query<TPart, TRecord>().List() :
                Services.ContentManager.Query<TPart, TRecord>().Where(filter).List();
        }

【问题讨论】:

  • 能否请您发布准确的错误信息?您还可以发布ReportPartReportRecord 的继承层次结构吗?
  • 根据您的错误消息,问题是由您传递给 BuildModel 的参数引起的。你怎么称呼它?
  • 调用GetList 时没有出错。调用 BuildModel 时出错,您未在此处显示。
  • 好吧,BuildModel 正在将Expression&lt;Func&lt;TRecord, bool&gt;&gt; 传递给一个应该是Expression&lt;Func&lt;ReportRecord, bool&gt;&gt; 的参数。我认为那行不通。委托协变和逆变是有限的,在这里,你不知道TRecord 实际是什么类型。最重要的是,您将其包装在 Expression 中,这可能会使逆变根本不起作用。
  • 协变和逆变不起作用。试试这条线 var items = GetList&lt;TPart, TRecord&gt;(predicate); 应该可以工作。

标签: c# linq parameters predicate


【解决方案1】:

如果没有a good, minimal, complete code example,就不可能确定最适合您的问题的解决方法是什么,假设存在一个问题。

也就是说,方差问题通常有两种形式:1) 你正在做的事情确实是错误的,编译器正在拯救你,以及 2) 你正在做什么're doing 并不能证明是正确的,所以你必须向编译器保证你知道你在做什么。

如果您属于第一类,那么一切都会丢失。你不能让它工作。

但是,如果您属于第二类,则可以通过将原始谓词包装在与被调用方法的要求兼容的新谓词中来使调用生效:

IEnumerable<ReportPart> items =
    GetList<ReportPart, ReportRecord>(r => predicate((TRecord)r));


就是说,尽管您以这种方式编写代码可能有一些重要原因,但鉴于您到目前为止所展示的少量代码,尚不清楚您为什么要尝试采用通用谓词并将其强制具体类型。

根据其余代码中实际发生的情况,像这样的一对通用方法在您 1) 完全通用的情况下会更好地工作(即不要强制类型为ReportRecord 在对 GetList()) 或 2) 的调用中,您根本不用担心泛型类型(即从 BuildModel() 方法中省略 TPartTRecord )。

1) 示例:

public IEnumerable<ViewModel> BuildModel<TPart, TRecord>(
    Expression<Func<TRecord, bool>> predicate) 
        where TPart : ContentPart<TRecord>
        where TRecord : ContentPartRecord
{
    IEnumerable<TPart> items = GetList<TPart, TRecord>(predicate);
}

2) 示例:

public IEnumerable<ViewModel> BuildModel(
    Expression<Func<ReportRecord, bool>> predicate)
{
    IEnumerable<ReportPart> items = GetList<ReportPart, ReportRecord>(predicate);
}

混合和匹配,即使您可以使其正常工作,也通常表明架构中存在更基本的问题,即泛型要么在不应该使用的地方使用,要么没有被采用优势以及应有的优势。


如果以上内容不能让你回到正轨,你真的应该通过提供一个最小的、完整的代码示例来改进这个问题。

【讨论】:

  • 更改为示例二以使其正常工作。我已经对它进行了很多修改,这就是为什么你看到通用和非混合的原因。无论如何,示例二实际上是我想要实现的。
猜你喜欢
  • 2012-06-16
  • 1970-01-01
  • 2012-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多