Apologies if this would be a better fit for the software engineering stack exchange, but as this is fairly language-specific, I believe I'm asking in the right place.
I have a project which involves converting a sizable codebase from Java to C#. The original Java project has an interface roughly equivalent to the following C# snippet.
public interface IEntry<out T> where T : class, IEntry<T>{ T SetName(string nameIn); string GetName(); } It also contains a basic implementation of this interface.
public abstract class BaseEntry<T> : IEntry<T> where T : BaseEntry<T>{ private string name; internal object extraData; public T SetName(string nameIn){ name = nameIn; return (T)this; } public string GetName(){ return name; } } The problem arises in the class which holds entries of types implementing the IEntry<T> interface.
public class ObjectHolder<T> where T : class, IEntry<T>{ private readonly List<T> entries; private readonly bool canGetExtraData; public ObjectHolder(){ //HasGenericBaseType simply checks if the first type implements the second type canGetExtraData = HasGenericBaseType(typeof(T), typeof(BaseEntry<>)); } public void Add(T entry){ entries.Add(entry); } public void DoSomething(int index){ if(!canGetExtraData){ T entry = entries[index]; object extraData = ((BaseEntry<T>)entry).extraData; <-- This cast fails on compilation //Something gets done with the extraData object } } } The indicated line gives me the below error on compilation.
error CS0314: The type `T' cannot be used as type parameter `T' in the generic type or method `BaseEntry<T>'. There is no boxing or type parameter conversion from `T' to `BaseEntry<T>' I understand why I get this error, but I'm struggling to find a way around it. How could the above class be redesigned to allow access to the internal object field on types extending BaseEntry<T>?
(object)to get around error at casting time... so not closing as duplicate).BaseEntry<T>is not equal toIEntry<T>You have a mammal that implementsILegs. but not everything that hasILegsis a mammal. Is there any reason you cant pushextraDataback to interface? Also there is other really suspect stuff going on here, like HasGenericBaseType. unfortunately with this sort of question, a concrete answer is problematic as we have no idea what problems you are trying to solveT extraData { get; set; }on the interface? Incidentally this whole pattern you describe is very similar to Curiously Recurring Template Patterninternal interface IExtraDatawith no generic constraint, then you won't need to prove to the compiler thatT : BaseEntry<T>. That simplifiescanGetExtraDatatoif (entries[index] is IExtraData extra) ... extra.extraData;