简体   繁体   中英

Casting with Generic Types

I'm pretty sure there is a simple answer to this that revolves around co-variance but I'm struggling to see it!

I have a class like so:

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; }
}

I then create an instance of a class that implements ICallbackMessageBase called Foo and instantiate a new GenericCallbackClass passing this in as the argument for T eg var myCallback = new GenericCallback<Foo>("SomeID", new Foo())

I now want to cast this to a more generic instance of the GenericCallbackClass because I will have many instances of this with Foo, Bar etc but all implement ICallbackMessageBase.

So I want to do something like var callback = myCallback as GenericCallbackClass<ICallbackMessageBase>

It appears I can't do this cast... Any ideas how I should get around this?

Why do you need Generic <T> 's at all in this situation. Is there some other code in your GenericCallback class that leverages <T> . Otherwise you can just rely on the interface implementation of each object and ensure that the Interface defines any common properties or operations you may need in your Callback class.

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());
}

Have you considered using an intermediate base class?

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

    public ICallbackMessageBase Message { get; private set; }
}

You can then derive the generic version from that:

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

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

It's basically just a wrapper that adds type checking and automatic casting for the message property. You will then be able to do this:

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

The g.Message property will be of type A , whereas the g2.Message property will be of type ICallbackMessageBase .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM