将产量线提取到通用方法中
我们在代码中使用自动生成的代码(带有存储库模式的 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
更新:您的问题与
yield
关键字无关。它与类型差异有关。您的 AcceptChangesAndYield 方法返回一个实现 IEnumerable类型的对象(事实上,它是编译器生成的类型,但这并不重要)。在您的方法调用中,您尝试将其向下转换为
IEnumerable
,这是更具体的。IEnumerable
接口是协变的,它允许您向上转换为不太具体的类型;例如,您可以从List
转换为IEnumerable
幸运的是,解决方案非常简单。重新定义您的
AcceptChangesAndYield
方法,如下所示:这将依次允许您的
GetAll
方法实现如下:原始答案:看来您只是想要这个吗?
然后在您想要删除重复的代码中,您只需:
对吗?还是我误解了你的问题?
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 implementingIEnumerable<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 anIEnumerable<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 aList<string>
to anIEnumerable<object>
(in .NET 4.0, anyway). The type generated by the compiler to supply the return value of yourAcceptChangesAndYield
method only implementsIEnumerable<MyModels.Interfaces.ILookup>
, so you could cast the result to anIEnumerable<object>
(for instance), but not to anIEnumerable<MyModels.StatusLookup>
.Fortunately, the solution is pretty simple. Redefine your
AcceptChangesAndYield
method as follows:This will in turn allow your
GetAll
method to be implemented as follows:Original Answer: It seems like you just want this?
Then in your code where you want to remove duplication, you'd just have:
Right? Or am I misunderstanding your problem?