2

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

Ramaraj T
  • 5,184
  • 4
  • 35
  • 68
  • 1
    You should declare your class like `public abstract class ChainedItem` to make the type `R` available in your class – Corentin Pane Jul 08 '20 at 07:36
  • 4
    Seems to me like you're looking to build a Monad. The best explanation of Monads for c# programmers I've found so far [is this one.](https://mikhail.io/2018/07/monads-explained-in-csharp-again/) – Zohar Peled Jul 08 '20 at 07:40
  • Quick thought, Use OOP concept, introduce class or interface like IChainable, add where T: IChainable and instead of R use the concrete interface IChainable. All your model will need to implement this Interface and it will work and look great, hope ^^. – Paweł Górszczak Jul 08 '20 at 20:57

2 Answers2

1

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);
  }
}
-1

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;
    }
    
    
   
}
tonydev314
  • 241
  • 1
  • 2
  • 10
  • I need to have the reference to the object in the same class. For e.g, in your code, private ChainedItem m_chainedItem; won't work because oSbject is not defined. – Ramaraj T Jul 08 '20 at 08:00
  • Define it as object and do an explicit cast to set it – tonydev314 Jul 08 '20 at 08:23