将yield line提取为常用方法

我们使用自动生成的代码(SubSonic3和Repository模式)和我们的代码,有很多这样的行。
public IEnumerable<MyModels.StatusLookup> GetAll()
    {
        var results = Database.Current.pStatusLookupLoadAll()
            .ExecuteTypedList<MyModels.StatusLookup>();
        if (results.IsNull()) yield break;
        foreach (var m in results)
        {
            ..Common logic lines...
            ..Common logic lines...
            yield return m;
        }
    }
我想要做的是将产量线重构为一种常用方法。但我不知道我是否可以因为收益率的方式而起作用。 然后,当我们有自定义代码调用存储库自动生成代码之外的数据库时,我可以在加载的模型对象上调用此常用方法。
public IEnumerable<Books> GetByFancy(int anInteger)
{
    DB db = Database.Current;
    var r = from b in db.Books
            join a in db.Authors on b.AuthorId equals a.AuthorId
            where a.AuthorId == anInteger
            select b;

    if (r.IsNull()) yield break;
    foreach (var m in r)
    {
        m.AcceptChanges();
        yield return m;
    }
}
所以上面的例子中有常见的重复行,我想在这里做一个常见的方法调用来删除常见的重复代码行。 这是我得到的例外。
System.InvalidCastException : Unable to cast object of type '<AcceptChangesAndYield>d__6' to type 'System.Collections.Generic.IEnumerable`1[MyModels.StatusLookup]'.

public IEnumerable<MyModels.StatusLookup> GetAll()
{
    var results = Database.Current.pStatusLookupLoadAll()
        .ExecuteTypedList<MyModels.StatusLookup>();
    return (IEnumerable<MyModels.StatusLookup>)results.AcceptChangesAndYield();
}
这是我尝试过的扩展方法。
public static class BaseModelExtensions
{
    public static IEnumerable<MyModels.BaseModel> AcceptChanges(this IEnumerable<MyModels.BaseModel> obj)
    {
        if (obj.IsNull()) yield break;
        foreach (var m in obj)
        {
            m.AcceptChanges();
            yield return m;
        }
    }

    public static IEnumerable<MyModels.Interfaces.ILookup> AcceptChangesAndYield(this IEnumerable<MyModels.Interfaces.ILookup> obj)
    {
        if (obj.IsNull()) yield break;
        foreach (var m in obj)
        {
            yield return m;
        }
    }
}
    
已邀请:
更新:您的问题与
yield
关键字无关。它与类型差异有关。 你的
AcceptChangesAndYield
方法返回一个实现
IEnumerable<MyModels.Interfaces.ILookup>
的类型的对象(实际上它是一个编译器生成的类型,但这并不重要)。在你的方法调用中,你试图将其转换为
IEnumerable<MyModels.StatusLookup>
,这更具体。
IEnumerable<T>
接口是协变的,它允许你向上转换为不太具体的类型;例如,你可以从
List<string>
转换为
IEnumerable<object>
(在.NET 4.0中,无论如何)。由编译器生成的用于提供
AcceptChangesAndYield
方法的返回值的类型仅实现
IEnumerable<MyModels.Interfaces.ILookup>
,因此您可以将结果转换为
IEnumerable<object>
(例如),但不能转换为
IEnumerable<MyModels.StatusLookup>
。 幸运的是,解决方案非常简单。重新定义
AcceptChangesAndYield
方法如下:
// Note: We are using a generic type constraint on T.
public static IEnumerable<T> AcceptChangesAndYield<T>(this IEnumerable<T> obj)
    where T : MyModels.Interfaces.ILookup
{
    if (obj.IsNull()) yield break;
    foreach (var m in obj)
    {
        // Did you mean to put m.AcceptChanges() here?
        yield return m;
    }
}
这将允许您的
GetAll
方法实现如下:
public IEnumerable<MyModels.StatusLookup> GetAll()
{
    var results = Database.Current.pStatusLookupLoadAll()
        .ExecuteTypedList<MyModels.StatusLookup>();
    // Note: no need for a cast, as the return value is now
    // already strongly typed as IEnumerable<MyModels.StatusLookup>.
    return results.AcceptChangesAndYield();
}
原答案:好像你只想要这个?
IEnumerable<T> EnumerateResults<T>(IEnumerable<T> results)
{
    if (results.IsNull()) yield break;
    foreach (T result in results)
    {
        // ..Common logic lines...
        yield return result;
    }
}
然后在您要删除重复的代码中,您只需:
// Specific stuff
var results = BlahBlahBlah();

// Common stuff
return EnumerateResults(results);
对?或者我误解了你的问题?     

要回复问题请先登录注册