none
How to store tpl dataflow blocks in a list and link them dynamically RRS feed

  • Question

  • Hi

    My goal is to create a vanilla system with abstract classes that our junior programmers can simply inherit to accommodate

    needs of new clients. I have created a base abstract class with two lists of IDataflowBlock and a LinkToInputs method that will create a pipeline on startup, but am having a problem casting the IDataflowBlock's back to there actual types to do the link. I thought using dynamic types would do the trick, it compiles but the LinkTo method gives an error at run time.

    Each Dataflowblock in the list can be a different type and in addition each class inheriting can have one or more generic types that it supports so I cant create lists of the actual type or the generic types ISourceBlock<T> / ITargetBlock<T>

    Please note the following code is just test code to debug my problem. I have added two concrete classes to test my base class though in reality there will be several layers of abstraction to totally hide tpl dataflow from the implementers.

    Is there anyone who can assist me with the cast or suggest a better way to do this? Thanks in advance.

    namespace TestTPLDataflow
    {
        public abstract class BaseAbstractClass
        {
            protected List<IDataflowBlock> Inputs = new List<IDataflowBlock>();
            protected List<IDataflowBlock> Outputs=new List<IDataflowBlock>();
    
            public void LinkToInputs(BaseAbstractClass InputClass)
            {
                foreach (dynamic Input in Inputs)
                {
                    Type inputtype = Input.GetType().GenericTypeArguments[0];
    
                    foreach (dynamic Output in InputClass.Outputs)
                    {
                        Type outputtype = Output.GetType().GenericTypeArguments[0];
    
                        if (inputtype == outputtype)
                        {
                            Output.LinkTo(Input); //<-- Exception No overload for method 'LinkTo' takes '1' arguments
                        }
                    }
                }
            }
    
            /* This works perfectly
            public void LinkToInputs(BaseAbstractClass InputClass)
            {
                BufferBlock<string> Output = (BufferBlock<String>)InputClass.Outputs[0];
                ActionBlock<string> Input = (ActionBlock<string>)Inputs[0];
                Output.LinkTo(Input);
            }*/
        }
    
    
        public class ConcreteStartClass:BaseAbstractClass
        {
            BufferBlock<string> Output = new BufferBlock<String>();
    
            public ConcreteStartClass()
            {
                Outputs.Add(Output);
            }
    
            public void PostString(string InputString)
            {
                Output.Post(InputString);
            }
        }
    
        public class ConcreteEndClass:BaseAbstractClass
        {
            private void DoSomethingString(string inputstring)
            {
                Console.WriteLine(inputstring);
            }
    
            public ConcreteEndClass()
            {
                ActionBlock<string> Input = new ActionBlock<string>(input => DoSomethingString(input));
                Inputs.Add(Input);
            }
    
        }
    
        public class TestDataFlow2
        {
            ConcreteStartClass Start = new ConcreteStartClass();
            ConcreteEndClass End = new ConcreteEndClass();
    
            public void Init()
            {
                End.LinkToInputs(Start);
            }
    
            public void Test()
            {
                for (int i = 0; i < 1000; i++)
                {
                    Start.PostString(string.Format("Hello World {0}", i));
                }
            }
        }
    }

    Thursday, November 23, 2017 2:20 AM

Answers

  • The problem is that the overload of LinkTo you want to use is an extension method and extension methods don't work with dynamic. To fix that, you can invoke LinkTo as a static method:

    DataflowBlock.LinkTo(Output, Input);
    • Edited by svickMVP Thursday, November 23, 2017 10:30 PM
    • Marked as answer by Kenneth OHalloran Friday, November 24, 2017 11:17 AM
    Thursday, November 23, 2017 10:29 PM

All replies

  • The problem is that the overload of LinkTo you want to use is an extension method and extension methods don't work with dynamic. To fix that, you can invoke LinkTo as a static method:

    DataflowBlock.LinkTo(Output, Input);
    • Edited by svickMVP Thursday, November 23, 2017 10:30 PM
    • Marked as answer by Kenneth OHalloran Friday, November 24, 2017 11:17 AM
    Thursday, November 23, 2017 10:29 PM
  • Awesome yes that works. Thank you :)
    Friday, November 24, 2017 11:17 AM