Lambda表达式转换

4

我该如何将数据类型从

Expression<Func<T, bool>> predicate

为了

Expression<Func<SomeType, bool>> predicate

迄今为止还没有找到方法。或者至少可以通过使用第一个表达式的谓词的字符串表示来创建一个新的Expression<Func<SomeType, bool>>

如果有帮助,T仅限于实现了ISomeInterface的类型,并且SomeType实现了它。

LE:进一步澄清

接口类似于:

public interface ICacheable
{
    List<T> GetObjects<T>(Expression<Func<T, bool>> predicate) where T : ICacheable;
}
那么你需要:
public partial class Video : ICacheable
{
    public List<T> GetObjects<T>(Expression<Func<T, bool>> predicate) where T : ICacheable
    {
        // implementation here that returns the actual List<Video>
        // but when I try to query the dbcontext I can't pass a predicate with type T, I have to cast it somehow
        List<Video> videos = db.Videos.Where(predicate).ToList(); // not working
    }
}
那么你就有:
public class RedisCache
{
    public List<T> GetList<T>(Expression<Func<T, bool>> predicate) where T : ICacheable
    {
        List<T> objList = // get objects from cache store here
        if(objList == null)
        {
            List<T> objList = GetObjects<T>(predicate);
            // cache the result next
        }
        return objList;
    }
}

我可以像这样从任何类使用上述代码:

// If the list is not found, the cache store automatically retrieves 
// and caches the data based on the methods enforced by the interface
// The overall structure and logic has more to it. 
List<Video> videos = redisCache.GetList<Video>(v => v.Title.Contains("some text"));
List<Image> images = redisCache.GetList<Image>(v => v.Title.Contains("another text"));

我希望将这种缓存扩展到任何需要进行缓存的对象,使用方法可以自动检索实体或实体列表,如果它们在缓存中不存在。不过,我可能做错了。


6
如果传递给它的是ISomeInterface的另一种实现,而不是SomeType,你会期望发生什么? - Jon Skeet
转念一想,我不确定这是否是重复的问题,但您可能仍然想阅读该问题。如果您需要做的不仅仅是愚蠢的类型替换,那么请接受我的慰问。 - Jon
@Jon 这确实是一个精确的副本。 - usr
我已经编辑了你的标题。请参考“问题的标题应该包含“标签”吗?”,在那里达成共识是“不应该”。 - John Saunders
我添加了更多细节以防万一,我会查看重复内容,虽然我希望它更简单。谢谢。 - Mecca
2个回答

1

这是一些(极其)基础的内容,我希望它可以帮助您在使用泛型进行缓存的过程中。

// ICacheable interface is used as a flag for cacheable classes
public interface ICacheable
{
}

// Videos and Images are ICacheable
public class Video : ICacheable
{
    public String Title { get; set; }
}

public class Image : ICacheable
{
    public String Title { get; set; }
}

// CacheStore will keep all objects loaded for a class, 
// as well as the hashcodes of the predicates used to load these objects
public class CacheStore<T> where T : ICacheable
{
    static List<T> loadedObjects = new List<T>();
    static List<int> loadedPredicatesHashCodes = new List<int>();

    public static List<T> GetObjects(Expression<Func<T, bool>> predicate) 
    {

        if (loadedPredicatesHashCodes.Contains(predicate.GetHashCode<T>()))
            // objects corresponding to this predicate are in the cache, filter all cached objects with predicate
            return loadedObjects.Where(predicate.Compile()).ToList();
        else
            return null;
    }

    // Store objects in the cache, as well as the predicates used to load them    
    public static void StoreObjects(List<T> objects, Expression<Func<T, bool>> predicate)
    {
        var hashCode = predicate.GetHashCode<T>();
        if (!loadedPredicatesHashCodes.Contains(hashCode))
        {
            loadedPredicatesHashCodes.Add(hashCode);
            loadedObjects = loadedObjects.Union(objects).ToList();
        }
    }
}

// DbLoader for objets of a given class
public class DbStore<T> where T : ICacheable
{
    public static List<T> GetDbObjects(Expression<Func<T, bool>> predicate)
    {
        return new List<T>(); // in real life, load objects from  Db, with predicate
    }
}

// your redis cache
public class RedisCache
{
    public static List<T> GetList<T>(Expression<Func<T, bool>> predicate) where T:ICacheable
    {
        // try to load from cache
        var objList = CacheStore<T>.GetObjects(predicate);
        if(objList == null)
        {
            // cache does not contains objects, load from db
            objList = DbStore<T>.GetDbObjects(predicate);
            // store in cache
            CacheStore<T>.StoreObjects(objList,predicate);
        }
        return objList;
    }
}

// example of using cache
public class useRedisCache
{
    List<Video> videos = RedisCache.GetList<Video>(v => v.Title.Contains("some text"));
    List<Image> images = RedisCache.GetList<Image>(i => i.Title.Contains("another text"));
}

// utility for serializing a predicate and get a hashcode (might be useless, depending on .Equals result on two equivalent predicates)
public static class PredicateSerializer
{
    public static int GetHashCode<T>(this Expression<Func<T, bool>> predicate) where T : ICacheable
    {
        var serializer = new XmlSerializer(typeof(Expression<Func<T, bool>>));
        var strw = new StringWriter();
        var sw = XmlWriter.Create(strw);
        serializer.Serialize(sw, predicate);
        sw.Close();
        return strw.ToString().GetHashCode();
    }
}

1
我对Entity Framework不是很熟悉,但我知道LINQ中的DatabaseContext有一个GetTable方法,它根据泛型返回表格。如果"ObjectContext的GetTable等效方法"可行的话,那么在EF中也应该可用? 为了使你的语句真正通用,你可以尝试这个:
public MyBaseObject<T>
{
    public List<T> GetObjects<T>(Expression<Func<T, bool>> predicate) where T : ICacheable
    {
        return db.CreateObjectSet<T>().Where(predicate).ToList();
    }
}

public partial class Image : MyBaseObject<Image>, ICacheable
{
}

public partial class Video : MyBaseObject<Video>, ICacheable
{
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,