我创建了一个与我的缓存一起使用以获取缓存项的类。如果项目未缓存,则调用函数以获取实际值。
这个类有八个方法,除了它们调用的函数外,它们的代码几乎相同。我创建了一个名为GetObject的函数,如果它无法在类中找到项目,则会调用委托。
由于以下错误,我无法编译代码:
参数2:无法转换 '
System.Collections.Generic.List<string>
'到 'MyFunction<System.Collections.Generic.List<string>>
'。
我做错了什么,或者我正在尝试做一些无法做到的事情?
这是我正在尝试的代码。
public delegate T MyFunction<T>(string s);
public T GetCultures<T>(string s) where T : class {
return NewListOfStrings(s) as T;
}
public List<string> NewListOfStrings(string s) {
return new List<string> { s };
}
public List<string> GetListOfStrings(string sitename) {
string key = cachingService.CreateValidKey("stringvalue");
//This is the line that fails to compile
var foundItems = GetObject<List<string>>(key,
GetCultures<List<string>>(sitename));
return foundItems;
}
public T GetObject<T>(string key, MyFunction<T> f) where T : class {
T foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
lock (key) {
foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
foundItems = f as T;
if (foundItems != null) {
cachingService.SetCachedItem(key, foundItems, 5,
Constants.MINUTES);
}
}
}
}
return foundItems;
}
解决方案
public T GetObject<T>(string key, Func<T> getFromRepository) where T : class {
T foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
lock (key) {
foundItems = (T)cachingService.GetCachedItem(key);
if (foundItems == null) {
foundItems = getFromRepository() as T;
if (foundItems != null) {
cachingService.SetCachedItem(key, foundItems, 5,
Constants.MINUTES);
}
}
}
}
return foundItems;
}
public AreaModels.Site GetSiteByName(string sitename) {
string key = cachingService.CreateValidKey(
string.Format("Site_{0}", sitename));
return GetObject<AreaModels.Site>(key,
() => efRepository.GetSiteByName(sitename));
}
public List<AreaModels.Culture> GetCulturesForSite(string sitename) {
string key = cachingService.CreateValidKey(
string.Format("Cultures_{0}", sitename));
return GetObject<List<AreaModels.Culture>>(key,
() => efRepository.GetCulturesForSite(sitename));
}
public List<AreaModels.Resource> Resources(string sitename, int appId) {
string key = cachingService.CreateValidKey(
string.Format("ResourcesFor{0}", sitename));
return GetObject<List<AreaModels.Resource>>(key,
() => efRepository.GetResourcesBySiteAndAppId(sitename, appId));
}
答案 0 :(得分:3)
您传递的是函数的结果而不是函数本身。您可以像这样使用lambda:
var foundItems = GetObject<List<string>>(key,
name => GetCultures<List<string>>(sitename));
你也有这一行:
foundItems = f as T;
这里你试图将函数本身转换为它的返回类型,这将不起作用。相反,你可以这样做:
foundItems = f(name);
但现在您的问题是您必须将名称传递给GetObject
,否则无法在需要的地方访问该名称。这样做的原因是MyFunction
与string
之间存在不匹配,以及您真正想要的是什么,这是一个可以在GetObject
内进行评估而不需要name参数的函数被传入。
所以你应该做的是将你的代表改为:
public delegate T MyFunction<T>();
或者完全取消委托,并将f
参数设为Func<T>
。
使用这些选项之一,您可以传入lamba而不需要参数:
var foundItems = GetObject<List<string>>(key,
() => GetCultures<List<string>>(sitename));
并评估它:
foundItems = f();
请注意,创建一个lambda将其传递给另一个方法只是为了评估它而不是直接传递结果,这有点迂回。因此,除非在某些情况下您需要执行此操作,否则您可能希望更改f
参数以取代T
类型。在这种情况下,我怀疑你这样做是为了懒惰地评估函数,这样你就不必评估结果是否已经缓存了。这可能是一个正当的理由,假设您没有过早优化性能。
答案 1 :(得分:2)
您没有创建委托。实际上,在调用GetObject
之前,您正在评估该方法。轻松修复:
var foundItems = GetObject<List<string>>(key,
name => GetCultures<List<string>>(name));
另请注意,在此方案中,您对sitename
要做的事情并不明显;你可能代之以:
name => GetCultures<List<string>>(sitename));
答案 2 :(得分:0)
这是一个完整的例子
public class TestDelegate
{
//You don't need generic here if you always return a list of string
public List<string> GetCulture(string s)
{
return new List<string> { s };
}
public T GetObject<T>(string key, Func<string, T> fn)
{
T foundItems = fn(key);
return foundItems;
}
public void Test()
{
List<string> test = GetObject("abc", x => GetCulture(x));
}
}
如果你看一下方法Test()和GetObject(),你可以注意到3个有趣的事情: