2012-09-12 167 views
4

我很确定有一个简单的答案,围绕着协变,但我很难看到它!使用泛型类型铸造

我有一个类,如下所示:

internal sealed class GenericCallbackClass<T> : SomeBaseClass 
    where T : ICallbackMessageBase 
{ 
    public GenericCallbackClass(string activeId, T message) 
     : base(activeId) 
    { 
     Message = message; 
    } 

    public T Message { get; private set; } 
} 

我然后创建实现ICallbackMessageBase叫Foo的一个类的实例和实例在此传递作为参数对于T 例如一个新GenericCallbackClass var myCallback = new GenericCallback<Foo>("SomeID", new Foo())

我现在想把它转换为GenericCallbackClass的更通用的实例,因为我将有许多Foo,Bar等实例,但都实现ICallbackMessageBase。

所以,我要像做var callback = myCallback as GenericCallbackClass<ICallbackMessageBase>

看来我不能这样做投...任何想法,我应该怎么解决这个问题?

+1

搜索“co-and contra-variance”,这里有很多关于你的问题。 –

+3

你为什么在这里使用泛型?为什么不是非泛型类,使用'ICallbackMessageBase Message'? – svick

+0

@svick同上...想着同样的事情。 –

回答

5

为什么在这种情况下您需要通用<T>。 GenericCallback类中是否有其他代码利用<T>。否则,您可以只依赖每个对象的接口实现,并确保接口定义您的Callback类中可能需要的任何公共属性或操作。

public class SomeBaseClass 
{ 
    public SomeBaseClass (string activeId) 
    { 
     //Persist activeId 
    } 
} 

public interface ICallbackMessageBase { /* implementation */ } 
public class Foo : ICallbackMessageBase { /* implementation */ } 

internal sealed class GenericCallbackClass : SomeBaseClass 
{ 
    public GenericCallbackClass(string activeId, ICallbackMessageBase message) 
     : base(activeId) 
    { 
     Message = message; 
    } 

    public ICallbackMessageBase Message { get; private set; } 
} 

void Main() 
{ 
    var specific = new GenericCallbackClass("foo", new Foo()); 
} 
+0

我认为你的代码不会做你认为它的工作。类型参数通常被命名为'T'或类似的东西,但你有一个名为'ICallbackMessageBase'。这非常令人困惑,因为该类型参数与实际接口类型“ICallbackMessageBase”没有关系。您应该完全删除该类型参数。 – svick

+0

jeepers。完全错过了。在LinqPad中没有语法突出显示,只是一味地复制了这些内容:\ –

+0

Err ...怯懦地想知道为什么我自己介绍泛型。我必须把它放到那些日子中的一个!谢谢您的帮助。 – user630190

1

你有没有考虑过使用中间基类?

internal class GenericCallbackClassBase 
{ 
    public GenericCallbackClassBase(ICallbackMessageBase message) 
    { 
     Message = message; 
    } 

    public ICallbackMessageBase Message { get; private set; } 
} 

然后,您可以从中导出通用版:

internal sealed class GenericCallbackClass<T> : GenericCallbackClassBase 
where T : ICallbackMessageBase 
{ 
    public GenericCallbackClass(T message) 
     : base(message) { } 

    public new T Message 
    { 
     get { return (T)base.Message; } 
    } 
} 

它基本上只是增加了类型检查和消息属性自动注入的包装。然后,您就可以做到这一点:

var g = new GenericCallbackClass<A>(a); 
var g2 = g as GenericCallbackClassBase; 

g.Message属性为A型的,而g2.Message属性将是ICallbackMessageBase类型。