James P. Wright
James P. Wright

Reputation: 9131

C# Interface enforcing property that is another Interface?

Given this code:

public interface ITagModel { }

public interface ITemplate {
    ITagModel Model { get; set; }
}

public class EmailTag : ITagModel { }

public class EmailTest : ITemplate {
    public EmailTag Model { get; set; }
}

I am being told that the Type of EmailTag (inside EmailClass) cannot implement the Property Model because it is not the type ITagModel.

It is inheriting ITagModel....so why won't this work? What can I do to accomplish what I'm looking for?

Upvotes: 1

Views: 463

Answers (2)

Dustin Kingen
Dustin Kingen

Reputation: 21245

C# doesn't support covariant return.

e.g.

public class Base { }
public class Derived : Base { }

public class Component
{
    public virtual Base GetComponent()
    {
        return new Base();
    }
}

public class DerviedComponent : Component
{
    public override Dervied GetComponent()
    {
        return new Derived();
    }
}

So you'll need to abstract the return type and constrain it to your interface. That way any implementation will need to supply an ITagModel.

public interface ITagModel { }

public interface ITemplate<TModel>
    where TModel : ITagModel
{
    TModel Model { get; set; }
}

public class EmailTag : ITagModel { }

public class EmailTest : ITemplate<EmailTag> {
    public EmailTag Model { get; set; }
}

Upvotes: 5

Jon Skeet
Jon Skeet

Reputation: 1500755

It sounds like your ITemplate interface should be generic:

public interface ITemplate<TModel> where TModel : ITagModel
{
    TModel Model { get; set; }
}

Then:

public class EmailTest : ITemplate<EmailTag>
{
    public EmailTag Model { get; set; }
}

Imagine if your current code worked. I could then write:

ITemplate template = new EmailTest();
template.Model = new SomeOtherModel();

... and you wouldn't want that. (Basically, you'd be violating type safety.)

Upvotes: 2

Related Questions