将产量线提取到通用方法中

发布于 2024-10-30 10:57:35 字数 2158 浏览 4 评论 0原文

我们在代码中使用自动生成的代码(带有存储库模式的 SubSonic3),并且有很多这样的行。

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

We are using autogenerated code (SubSonic3 with Repository pattern) with our code and there are many lines like this.

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

What I would like to do is refactor out the yield lines into a common method. But I don't know if I can due to the way yield works.

Then when we have custom code that calls the db outside of the repository auto generated code I can then call this common method on the loaded model objects.

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

So the above example has the common repeat lines in it where I'd like to make a common method call to remove the common repeat code lines.


Here is the exception that I get.

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

And here is the extension method that I tried this with.

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

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

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

发布评论

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

评论(1

猫性小仙女 2024-11-06 10:57:35

更新:您的问题与 yield 关键字无关。它与类型差异有关。

您的 AcceptChangesAndYield 方法返回一个实现 IEnumerable类型的对象(事实上,它是编译器生成的类型,但这并不重要)。在您的方法调用中,您尝试将其向下转换IEnumerable,这是更具体的

IEnumerable 接口是协变的,它允许您向上转换不太具体的类型;例如,您可以从 List 转换为 IEnumerable(无论如何,在 .NET 4.0 中)。编译器生成的用于提供 AcceptChangesAndYield 方法的返回值的类型仅实现 IEnumerable,因此您可以将结果转换为 >IEnumerable(例如),但不是IEnumerable

幸运的是,解决方案非常简单。重新定义您的 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);

对吗?还是我误解了你的问题?

Update: Your problem is not related to the yield keyword specifically. It has to do with type variance.

Your AcceptChangesAndYield method returns an object of a type implementing IEnumerable<MyModels.Interfaces.ILookup> (in fact it is a compiler-generated type, but that's not really important). In your method call you are trying to downcast this to an IEnumerable<MyModels.StatusLookup>, which is more specific.

The IEnumerable<T> interface is covariant which would allow you to upcast to a less specific type; e.g., you could cast from a List<string> to an IEnumerable<object> (in .NET 4.0, anyway). The type generated by the compiler to supply the return value of your AcceptChangesAndYield method only implements IEnumerable<MyModels.Interfaces.ILookup>, so you could cast the result to an IEnumerable<object> (for instance), but not to an IEnumerable<MyModels.StatusLookup>.

Fortunately, the solution is pretty simple. Redefine your AcceptChangesAndYield method as follows:

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

This will in turn allow your GetAll method to be implemented as follows:

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

Original Answer: It seems like you just want this?

IEnumerable<T> EnumerateResults<T>(IEnumerable<T> results)
{
    if (results.IsNull()) yield break;
    foreach (T result in results)
    {
        // ..Common logic lines...
        yield return result;
    }
}

Then in your code where you want to remove duplication, you'd just have:

// Specific stuff
var results = BlahBlahBlah();

// Common stuff
return EnumerateResults(results);

Right? Or am I misunderstanding your problem?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文