T类型的动态通用声明

时间:2009-10-04 13:15:52

标签: c# generics types

我有一个存储类型字典的数组:

//The dictionary:
Dictionary<CacheKey,Type> TypeLookup;

//This is the enum:
public enum CacheKey
{
    UserProfile,
    CustomerQuickSearch,
    CommissionConfiguration
}

我想使用这个Dictionary来声明一个T

类型的变量
        //instead of 
        T myvar;

        //I want to dynamically declare myvar as:
        //1)get the type for the cacheKey from the dictionary:
        Type type = TypeLookup[cacheKey];
        //2)declare myvar as the corresponding Type:
        type myvar;

背景是我正在构建分布式缓存基础结构。我有一个很棒的CachingProvider,它允许你更新缓存中的项目。

我想将此方法公开为Web服务,以便我的服务器场中的所有服务器都可以更新其缓存。但我希望只有一个方法作为Web服务公开,然后更新缓存中的相应项目。

这是我试图揭露的方法:

   public static void UpdateCacheEntryItem<T>(CacheKey cacheKey, int id)
    {
        //look up the cacheEntry in cache which is a dictionary.
        Dictionary<int, T> cacheEntry = (Dictionary<int, T>) CacheRef[cacheKey.ToString()];

        //call the corresponding method which knows how to hydrate that item and pass in the id.
        cacheEntry[id] = (T)HydrateCacheEntryItemMethods[cacheKey].Invoke(id);
    }

我尝试过的事情: 1)我尝试将该方法直接暴露为WCF服务,但当然由于该方法而无效。 2)我尝试编译将要查找的字典,因为我不需要使用返回值进行anthing,我只需要更新缓存中的项目。但这也不起作用。我得到错误:无法转换类型为'System.Collections.Generic.Dictionary 2[System.Int32,CachingPrototype.CustomerQuickSearch]' to type 'System.Collections.Generic.Dictionary 2 [System.Int32,System.Object]'的对象。

您的评论非常有用,帮助我回答了我的问题。我想出的解决方案是简单地将我的WCF服务方法包装在switch语句中,这样我就可以使用正确的T类型调用UpdateCacheEntryItem方法。由于无法从Type转换为泛型T运算符,这是唯一的选择。由于我在Cache中没有那么多类型,因此效果很好。 (另一个解决方案是使用如下所述的接口,但不会像我希望的那样强类型。)

    [OperationContract]
    public void UpdateCacheEntryItem(CacheKey cacheKey, int id)
    {
        switch (cacheKey)
        {
            case CacheKey.UserProfile:
                CacheProvider.UpdateCacheEntryItem<UserProfile>(cacheKey, id);
                break;
            case CacheKey.CommissionConfig:
                CacheProvider.UpdateCacheEntryItem<CommissionConfig>(cacheKey, id);
                break;
            case CacheKey.CustomerQuickSearch:
                CacheProvider.UpdateCacheEntryItem<CustomerQuickSearch>(cacheKey, id);
                break;
            default:
                throw new Exception("Invalid CacheKey");
        }

感谢大家的帮助,你们很棒!

2 个答案:

答案 0 :(得分:10)

“动态声明变量”的想法与作为变量声明的一部分的类型的整体观点相反。这个想法是你可以告诉编译器类型,以便它可以检查你正在做什么。在这种情况下,您根本没有表达任何类型的信息。您也可以将myVar声明为object类型;这基本上与说“我对myVar的价值几乎一无所知,除了它是一个参考。”

如果你有一个共同的界面当然,这将是伟大的 - 然后你可以安全地使用该界面的成员(当然,在创建/获取适当的实例之后)。但除此之外,除非你在编译时知道关于类型的某些东西,否则你真的没什么可做的。

在C#4中,您可以将变量声明为类型dynamic,这将使所有绑定动态 - 基本上您可以使用它完成您喜欢的任何操作,并且它将在执行时解决。我建议尽可能使用静态类型,以便在编译时捕获错误。

答案 1 :(得分:2)

在我看来,界面和一些演员会解决你的问题。让每个可缓存的类实现一个接口。在您的字典中存储此类型的项目。据推测,CacheRef的类型为Dictionary<CacheKey,Dictionary<CacheKey,ICacheable>>。剩下的就是确保可缓存的类实现接口。

public interface ICacheable
{
}

public static void UpdateCacheEntryItem(CacheKey cacheKey, int id)
{
    //look up the cacheEntry in cache which is a dictionary.
    Dictionary<CacheKey,ICacheable> cacheEntry = CacheRef[cacheKey.ToString()];

    //call the corresponding method which knows how to hydrate that item and pass in the id.
    cacheEntry[id] = (ICacheable)HydrateCacheEntryItemMethods[cacheKey].Invoke(id);
}

请注意,这不是,就像@Jon Skeet在他的回答评论中所说,强制执行词典中的类型。这取决于您的代码,以确保您将正确类型的对象放入每个缓存中。只要您的水合方法被单元测试所覆盖,我就会对此感到满意,以确保在给定特定键时,它们始终会生成相应类型的对象。