不知道(或需要)特定类型的Generic

时间:2011-11-18 15:24:06

标签: .net generics inheritance

我处于第三方控件做某事的情况,这被设置为通用。出于UI原因,我坚持使用此对象。我也有自己的控件,它与我们的数据层接口来做那件事,并在类型 对象 上进行。没有必要的泛型。它弄清楚要做什么,做什么。

这是他们结构的精简版本(注意:我不能改变它。)

public enum ThirdPartyTypesOfActions
{
    ThirdPartyDoAction1WithThing,
    ThirdPartyDoAction2WithThing,
    ThirdPartyDoAction3WithThing
}

public class ThirdPartyActionsToDo
{
    public ThirdPartyTypesOfActions TypeOfAction;
}

public class ThirdPartyDoAction1WithThing<T> : ThirdPartyActionsToDo
{
    public T Thing;
    public Type ThingType;
}

我的:

public enum MyActionTypes
{
    Action1,
    Action2,
    Action3
}

public class MyAction
{
    public object Thing;
    public MyActionTypes ActionToPerform;
}

所以我有一个转换器,看起来像:

public List<MyAction> ConvertTheirsToMine(List<ThirdPartyActionsToDo> actions)
{
    List<MyAction> retval=new List<MyAction>();

    foreach (ThirdPartyActionsToDo action in actions)
    {
        switch (action.TypeOfAction)
        {
            case ThirdPartyTypesOfActions.ThirdPartyDoAction1WithThing:
                retval.Add(HandleAction1(action));
                break;
            default:
                //Yeah, there's more, but they're the same
                break;
        }
    }
    return retval;
}

所以有设置。现在我试图实现HandleAction1,这就是问题发生的地方。

这看起来很有希望并编译好:

private MyAction HandleAction1(ThirdPartyActionsToDo action)
    {
        MyAction retval=new MyAction();

        ThirdPartyDoAction1WithThing<object> fullyQualified = (ThirdPartyDoAction1WithThing<object>) action;

        retval.ActionToPerform = MyActionTypes.Action1;
        retval.Thing = fullyQualified.Thing;

        return retval;
    }

但是在运行时,它会引发异常,因为它无法强制转换ThirdPartyDoAction1WithThing&lt; string&gt; as ThirdPartyDoAction1WithThing&lt; object&gt;不好。

但是ThirdPartyActionsToDo给了我正在处理的对象的类型。也许我可以用它?

private MyAction HandleAction1(ThirdPartyActionsToDo action)
{
    MyAction retval=new MyAction();

    Type tt = action.ThingType;

    ThirdPartyDoAction1WithThing<tt> fullyQualified = (ThirdPartyDoAction1WithThing<tt>) action;

    retval.ActionToPerform = MyActionTypes.Action1;
    retval.Thing = (object)fullyQualified.Thing;

    return retval;
}

当然,这甚至都不会编译。

低技术“你无法从这里到达”解决方案是在action.ThingType上执行switch语句并单独处理我可能关心的每种类型。显然,我不太关心这个选项,因为我必须为每个动作类型执行此操作。有人看到了摆脱这种泥潭的方法吗?

2 个答案:

答案 0 :(得分:1)

由于您的示例似乎只需要转换为Generic类型是为了获取对Thing属性的引用,您可以使用反射来获取它而不使用强制转换:

    public static class PropertyExtractor
    {
        public static object GetProperty(object model, string propertyName)
        {
            var modelDescriptorCollection = TypeDescriptor.GetProperties(model);
            var modelData = modelDescriptorCollection.Find(propertyName, true);

            if (modelData != null)
            {
                return modelData.GetValue(model);
            }
            else
            {
                return null;
            }
        }
    }

使用此类,您可以像这样重写HandleAction1方法:

private MyAction HandleAction1(ThirdPartyActionsToDo action)
{
    MyAction retval=new MyAction();

    retval.ActionToPerform = MyActionTypes.Action1;
    retval.Thing = PropertyExtractor.GetProperty(action, "Thing");

    return retval;
}

答案 1 :(得分:0)

很遗憾这些类型属于第三方库;否则,协变接口或合适的非通用基类可以派上用场。

快速破解(如果你使用的是.NET 4,C#4)将是我们dynamic

private MyAction HandleAction1(ThirdPartyActionsToDo action)
{
    return new MyAction
    {
        ActionToPerform = MyActionTypes.Action,
        Thing = ((dynamic)action).Thing
    };
}

只要ThirdPartyActionsToDo action参数总是一个ThirdPartyActionsToDo<SomeType>,这应该可以正常工作。