Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
176 views
in Technique[技术] by (71.8m points)

c# - Cannot convert from generic type to interface

I'm getting an error when trying to add generic object to a List<>.

Its probably related to Covariance and Contravariance but I not sure how to work around this. I've tried to restrict my generic types using where T: IRegister.

I have an interface to represent a register and then two classes which represent a ByteRegister and a DoubleWordRegister.

public interface IRegister
{
    string Name {get;set;}
}

 public class ByteRegister : IRegister
{
...
}

public class DoubleWordRegister : IRegister
{
...
}

I then have another class which represents a block of these registers all of the same type.

public class RegisterBlock<T> where T:IRegister
{
   private IList<T> _registers;

 ... constructors, properties etc

    public void AddRegister(T register)
    {
        _registers.Add(register);
    }
}

And finally I have a RegisterMap class which is used to define the list of register blocks and each register within the block.

public class RegisterMap
{
    private List<RegisterBlock<IRegister>> _blocks;

    public RegisterMap()
    {
        _blocks = new List<RegisterBlock<IRegister>>();

        RegisterBlock<ByteRegister> block1= new RegisterBlock<ByteRegister>("Block1", 0);
        block1.AddRegister(new ByteRegister("Reg1"));
        block1.AddRegister(new ByteRegister("Reg2"));
        _blocks.Add(block1);

        RegisterBlock<DoubleWordRegister> block2= new RegisterBlock<DoubleWordRegister>("Block2", 10);
        block2.AddRegister(new DoubleWordRegister("Reg3"));
        block2.AddRegister(new DoubleWordRegister("Reg4"));
        block2.AddRegister(new DoubleWordRegister("Reg5"));
         _blocks.Add(block2);
    }
}

However I'm getting the following error:

Error 20 Argument '1': cannot convert from 'RegisterBlock<ByteRegister>' to 'RegisterBlock<IRegister>' on the line _blocks.Add(block1) and similarly on _blocks.Add(block2);

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I notice that you forgot to ask a question. You merely stated a bunch of facts. I'm going to assume your question is "why does the compiler produce this error?"

The compiler produces that error because to not produce that error would lead to a crash at runtime. Suppose we allowed:

List<RegisterBlock<IRegister> _blocks = new List<RegisterBlock<IRegister>>();
RegisterBlock<ByteRegister> block1= new RegisterBlock<ByteRegister>();
_blocks.Add(block1);  // Illegal, but suppose it was legal.

Now what stops this?

RegisterBlock<IRegister> block1Again = _blocks[0];

Nothing. _blocks is a list of RegisterBlock<IRegister>, so of course _blocks[0] is of type RegisterBlock<IRegister>. But remember that of course the first item in the list is actually a RegisterBlock<ByteRegister>.

Now what stops this?

block1Again.AddRegister(new DoubleWordRegister())?

Nothing. block1Again is of type RegisterBlock<IRegister>, which has a method AddRegister(IRegister), and DoubleWordRegister implements IRegister.

So you just put a double word register into a block that can only contain byte registers.

Clearly that is not safe. The only place where that can be made illegal at compile time is in the first step; the covariant conversion is not legal in the first place.

Incidentally, your question is often asked several times a day here. Twice so far this morning:

Implementing nested generic Interfaces


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...