nfplee
nfplee

Reputation: 7977

Inheritance Casting Using Interfaces Issue

I have the following model:

public interface IAntiSpam {
    string Name { get; }
    string Text { get; }
}

public interface IAntiSpamSubclass<T> where T : IAntiSpam {
    T Entity { get; set; }
}

public class Comment : IAntiSpam {
    public string Name { get; set; }
    public string Text { get; set; }
}

public class ForumPost : IAntiSpam {
    public User User { get; set; }
    public string Text { get; set; }
    public string Name { get return User.Name; }
}

public class ReportedData {        
    public string Reason { get; set; }
    public User ReportedBy { get; set; }
    public DateTime DateReported { get; set; }
}

public class CommentReported : ReportedData, IAntiSpamSubclass<Comment> {        
    public Comment Entity { get; set; }
}

public class ForumPostReported : ReportedData, IAntiSpamSubclass<ForumPost> {        
    public ForumPost Entity { get; set; }
}

This compiles which I take as a sign I'm on the right path.

Now given a List of ReportedData I need to loop over the data and display the Text property against the reported data. I could cast the ReportedData to the appropriate type and then access it from there. However I don't wish to do this as I need to be able to add additional types that inherit from ReportedData without having to modify the code which displays the Text property. This is where I figured my interfaces would help.

Here's the code I've tried to run:

var reportedData = GetReportedData(); // Returns IList<ReportedData>()

foreach (var data in reportedData) {
    var text = ((IAntiSpamSubclass<IAntiSpam>)data).Entity.Text;
}

However this gives the following error at run time:

Unable to cast object of type 'CommentReported' to type 'IAntiSpamSubclass`1[IAntiSpam]'.

I'd appreciate it if someone could help show me what I'm doing wrong. Thanks

Upvotes: 3

Views: 64

Answers (1)

p.s.w.g
p.s.w.g

Reputation: 149000

If the IAntiSpamClass<T> interface is made to be covariant with its type parameter, like this:

public interface IAntiSpamSubclass<out T> where T : IAntiSpam {
    T Entity { get; }
}

Then this cast will work. Note these changes:

  • Added the out modifier on the type parameter.
  • Removed the property setter.

Further Reading

Upvotes: 2

Related Questions