C#泛型集合

我是从 Java背景来到C#并且继续遇到与Java一样简单易用的泛型问题.

鉴于课程:

interface IUntypedField { }
class Field<TValue> : IUntypedField { }

interface IFieldMap
{
    void Put<TValue>(Field<TValue> field,TValue value);
    TValue Get<TValue>(Field<TValue> field);
}

我想写点类似的东西:

class Mapcopier
{
    void copy(IEnumerable<IUntypedField> fields,IFieldMap from,IFieldMap to)
    {
        foreach (var field in fields)
            copy(field,from,to); // <-- clearly doesn't compile as field is IUntypedField not Field 
    }

    void copy<TValue>(Field<TValue> field,IFieldMap to)
    {
        to.Put(field,from.Get(field));
    }
}

在Java中,这很容易解决,因为字段集合将是Iterable< Field<?>>你可以直接调用copy(Field,IFieldMap,IFieldMap).

在C#中,我发现自己正在为TValue的所有可能值进行切换/转换(可怕的气味,必须为您添加的每种类型添加一个案例显然是等待发生的错误,并且只有在类型集合有限时才可行):

foreach (var field in fields)
{
    switch (field.Type) // added an enum to track the type of Field's parameterised type
    {
    case Type.Int:   copy((Field<int>)field,to); break;
    case Type.Long:  copy((Field<long>)field,to); break; 
    ...
    }
}

我有时做的另一个选择是将功能移到Field类中,这又是一个很糟糕的问题.这不是该领域的责任.至少这可以避免巨大的转换:

interface IUntypedField { void copy(IFieldMap from,IFieldMap to); }
class Field<TValue> : IUntypedField 
{ 
    void copy(IFieldMap from,IFieldMap to)
    {
        to.Put(this,from.Get(this));
    }
}

...

    foreach (var field in fields)
        field.copy(from,to);

如果您可以编写多态扩展方法(即上面的IUntypedField和Field中的copy方法),那么您至少可以将代码放在与其职责相关的类旁边.

我错过了C#的一些功能,可以实现这一目标.或者是否有一些可以使用的功能模式?有任何想法吗?

(最后一件事,我目前仍然坚持使用.Net 3.5,因此不能使用任何协方差/逆变,但仍然有兴趣了解它们如何在这里提供帮助,如果有的话).

解决方法

这是一个完全类型安全的方法,它编译lambda来执行复制:
static class Mapcopier
{
    public static void copy(IEnumerable<IUntypedField> fields,to);
    }

    // cache generated copy lambdas
    static Dictionary<Type,Action<IUntypedField,IFieldMap>> copiers =
        new Dictionary<Type,IFieldMap>>();

    // generate copy lambda based on passed-in type
    static void copy(IUntypedField field,IFieldMap to)
    {
        // figure out what type we need to look up;
        // we kNow we have a Field<TValue>,so find TValue
        Type type = field.GetType().GetGenericArguments()[0];
        Action<IUntypedField,IFieldMap> copier;
        if (!copiers.TryGetValue(type,out copier))
        {
            // copier not found; create a lambda and compile it
            Type tFieldMap = typeof(IFieldMap);
            // create parameters to lambda
            ParameterExpression
                fieldParam = Expression.Parameter(typeof(IUntypedField)),fromParam = Expression.Parameter(tFieldMap),toParam = Expression.Parameter(tFieldMap);
            // create expression for "(Field<TValue>)field"
            var converter = Expression.Convert(fieldParam,field.GetType());
            // create expression for "to.Put(field,from.Get(field))"
            var copierExp =
                Expression.Call(
                    toParam,tFieldMap.getmethod("Put").MakeGenericmethod(type),converter,Expression.Call(
                        fromParam,tFieldMap.getmethod("Get").MakeGenericmethod(type),converter));
            // create our lambda and compile it
            copier =
                Expression.Lambda<Action<IUntypedField,IFieldMap>>(
                    copierExp,fieldParam,fromParam,toParam)
                    .Compile();
            // add the compiled lambda to the cache
            copiers[type] = copier;
        }
        // invoke the actual copy lambda
        copier(field,to);
    }

    public static void copy<TValue>(Field<TValue> field,from.Get(field));
    }
}

请注意,此方法即时创建复制方法,而不是调用copy< TValue>方法.这基本上是内联的,并且通过不进行额外呼叫来节省大约50ns的每次呼叫.如果要使copy方法更复杂,可能更容易调用copy而不是创建表达式树来内联它.

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...