How to use an object of a generic class inside a generic class in C#?

Viewed 109

I have a generic class. And this generic class needs to have another instance of the same class as one of its member.

Basically, I'm trying to achieve a sequence of operations. So every class will have to know the next item to continue the operation.

ChainedItem(Uri) -> ChainedItem(String) -> ChainedItem(MyClass) -> ....

This is what I have tried so far.

public abstract class ChainedItem<T>
{        
    private ChainedItem<R> m_chainedItem;

    public void SetNextChainedItem(ChainedItem<R> chainedItem)
    {
        m_chainedItem = chainedItem;
    }

    public abstract void DoOperation(T data);

    public virtual void ContinueNextOperation<R>(R data)
    {
        if(m_chainedItem != null)
            m_chainedItem.DoOperation(data);
    }
}

But I cannot use it like this, since R in line no #3 is not defined yet.

enter image description here

2 Answers

It's actually impossible because not supported by the compiler else it would cause a stack overflow of the compiler with such thing that is endless and so impossible, because of the generic type verification as currently defined by the .NET specifications that are more strict than templates in C++.

You could use a LinkedList<ChainedItem<>> but the diamond operator hence true generic polymorphism are not available in C#:

How to do generic polymorphism on open types in C#?

Therefore perhaps you can write such thing using an interface and type checking, excluding null values:

public interface IChainedItem
{
  void DoOperation(object value);
}
public abstract class ChainedItem<T> : IChainedItem
{
  private IChainedItem m_chainedItem;

  public void SetNextChainedItem(IChainedItem chainedItem)
  {
    m_chainedItem = chainedItem;
  }

  public abstract void DoOperation(T data);

  public virtual void ContinueNextOperation(object data)
  {
    if ( m_chainedItem != null )
      m_chainedItem.DoOperation(data);
  }

  public void DoOperation(object value)
  {
    if ( value == null )
      throw new ArgumentNullException();
    var typeIn = value.GetType();
    var typeRequired = typeof(T);
    if ( typeIn != typeRequired )
    {
      string message = $"Bad type in ChainedItem.DoOperation(object): "
                     + $"{typeRequired.Name} is required and not {typeIn.Name}.";
      throw new ArgumentException(message);
    }
    DoOperation((T)value);
  }
}

You will need to do something like this:

Code fiddle

    public class Program
    {
       public static void Main()
       {
         var testObj1 = new ChainedItem<int, string>();
         var testObj2 = testObj1.GetNextChainedItem<bool>();
        
         Console.WriteLine(testObj1.GetType().ToString());
         Console.WriteLine(testObj2.GetType().ToString());
        
       }
   }



   public class ChainedItem<T,R>
{        
    private object NextChainedItem;
    
    public ChainedItem<R,S> GetNextChainedItem<S>()
    {
        ChainedItem<R,S>NextChainedItem = new ChainedItem<R,S>();
        return NextChainedItem;
    }
    
    
   
}
Related