我们正在使用自动生成的代码(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;
}
}
我想要做的是将产量线重构为一种常用方法。但我不知道我是否可以因为收益率的方式而起作用。
然后,当我们有自定义代码在存储库自动生成的代码之外调用db时,我可以在加载的模型对象上调用这个公共方法。
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;
}
}
}
答案 0 :(得分:0)
更新:您的问题与yield
关键字无关。它与类型差异有关。
您的AcceptChangesAndYield
方法返回一个实现IEnumerable<MyModels.Interfaces.ILookup>
的类型的对象(实际上它是一个编译器生成的类型,但这并不重要)。在您的方法调用中,您正在尝试向下转换这个<{1}},这是更具体的。
IEnumerable<MyModels.StatusLookup>
界面协变,可让您向上转播到不太具体的类型;例如,您可以从IEnumerable<T>
转换为List<string>
(无论如何,在.NET 4.0中)。编译器为提供IEnumerable<object>
方法的返回值而生成的类型仅实现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;
}
}
右?或者我误解了你的问题?