我有class X
,它實現了interface IX
。我也有專門爲X的存儲庫類,它使用拉姆達expresions作爲參數:我可以在.NET 3.5中實現協變,C#
public interface IX
{
}
public class X : IX
{
....
}
public class XRepository : IRepository<X>
{
public IEnumerable<X> Filter(Func<X, bool> filterFunc)
{
...
}
}
我需要讓庫類的工作與接口IX
,所以我加IRepository<IX>
的接口正在實施:
public class XRepository : IRepository<X>, IRepository<IX>
{
public IEnumerable<X> Filter(Func<X, bool> filterFunc)
{
...
}
public IEnumerable<IX> Filter(Func<IX, bool> filterFunc)
{
// I need to call the same filter method as above, but
// in order to do so I must convert the Func<IX, bool> to Func<X, bool>.
}
}
我必須將Func<IX, bool>
轉換爲Func<X, bool>
,但由於代碼是使用.NET 3.5編寫的C#3.0,因此我無法從4.0中引入的類型協方差中受益。
一個簡單的解決方案可以使用Func<X, bool> newFunc = x => filterFunc(x);
,其中filterFunc
是Func<IX, bool>
類型。這會編譯,有人可能會期望它運行良好,但我認爲它不會。問題是我正在使用第三方框架來實現過濾器,即FluentNhibernate。我知道它使用表達式樹來剝離傳遞到lambda表達式成員訪問條件(如x => x.Name == "John"
)以構建本機SQL查詢(如WHERE Name = 'John'
)。上述解決方案將產生一個不是這種表達式的Func<X, bool>
,我擔心它將無法翻譯。所以我需要創建相同的lambda表達式,但使用兼容類型。知道X實現了IX,顯然Func<IX, bool>
中的任何代碼都可以用於X
類型的對象。然而,對我來說這並不明顯,我怎樣才能執行這種轉換。
我認爲這可以使用表達式樹來完成。我也擔心我的表現會受到很大的影響。即使我決定對我的場景採用另一種解決方案,我仍然會欣賞將一個lambda翻譯成另一個類似的方法的建議方法。
編輯:
爲了澄清更多關於我遇到的問題,我寫了下面的測試,模擬現實生活中的scenarion我面對:
Func<IX, bool> filter = y => y.Name == "John";
Func<X, bool> compatibleFilter = y => filter(y);
...
// Inside the Filter(Func<X, bool> filter method)
using(var session = nhibernateSessionFactory.OpenSession())
{
IEnumerable<X> xx = session.Query<X>().Where(z => compatibleFilter(z)).ToList();
}
如此,在ToList()
方法我收到以下異常
Unable to cast object of type 'NHibernate.Hql.Ast.HqlParameter' to type 'NHibernate.Hql.Ast.HqlBooleanExpression'.
這證實了我的假設,即Flunet NHiberante無法正確處理compatibleFilter參數。
所以我想要的是一種將Func轉換爲Func的方式,或者如John Skeet所建議的Expression<Func<IX, bool>>
至Expression<Func<X, bool>>
,它們具有相同的主體(y => y.Name = "John"
)。
編輯2:
最後我做了這一點!正確的方法不是使用Func<X, bool>
,而是使用Expression<Func<X, bool>>
。
Expression<Func<IX, bool>> filter = y => y.Name == "John Skeet";
Expression<Func<X, bool>> compatibleFilter = Expression.Lambda<Func<X, bool>>(
filter.Body,
filter.Parameters);
這產生了正確的SQL查詢。IX,bool
待辦事項你的意思是.NET 3.5?沒有C#3.5這樣的東西。 – 2012-03-11 20:24:02
是的,我的意思是.NET 3.5,但是我在某些地方見過C#3.0,我認爲我可以將它應用於3.5。我糾正自己 – 2012-03-11 20:31:07
請參閱http://stackoverflow.com/questions/247621/what-are-the-correct-version-numbers-for-c – 2012-03-11 20:33:47