Custom Activity - Change output type dynamically

I have the following class which represents my activity.

using System;
using System.Activities;
using System.Reflection;

namespace Tafs.Activities.Parsing
{
    public class TryParse : CodeActivity<bool>
    {
        public InArgument<Type> OutputType { get; set; }
        public InArgument<string> InputString { get; set; }
        public OutArgument<object> ParseResult { get; set; }

        protected override bool Execute(CodeActivityContext context)
        {
            Type type = OutputType.Get(context);
            var parseInputMethod = GetType().GetMethod(nameof(TryParse.ParseInput), BindingFlags.NonPublic | BindingFlags.Instance).MakeGenericMethod(type);

            return (bool)parseInputMethod.Invoke(this, new[] { context });
        }

        private bool ParseInput<T>(CodeActivityContext context)
        {
            string input = InputString.Get(context);

            if (Parser.GetParser<T>().Value is IParser<T> parser)
            {
                if (parser.TryParse(input, out T result))
                {
                    ParseResult.Set(context, result);
                    return true;
                }
            }

            return false;
        }
    }
}

This works pretty well, but I’d like to make some improvements.

Is it possible to have the type of ParseResult change to match the type selected in OutputType? I’m looking for this to function similarly to the System.Activities.Statements.Switch activity, where there is a type selector and choosing a different type selector replaces the activity with a string switch or an int switch or whatever the case may be.

End goal is I would like to avoid people having to manually cast back to the preferred type so as to emulate T.TryParse() as closely as possible.

Also, I’m working on figuring out a way to expand beyond the existing set of parsers. I’ve built a parser for each of C# types that have a TryParse method, but if you have a type that exists in a third party library, you’re SOL.

I do have these methods I built into my parsing library for further expansion later so I may build into that a bit.

/// <summary>
/// Registers a new parser or overwrites an existing parser for the specified type.
/// </summary>
/// <typeparam name="T">The type to provide a parser for</typeparam>
/// <param name="parser">The parser for this type.</param>
public static void SetParser<T>(IParser<T> parser) => TypeParsers[typeof(T)] = parser;

/// <summary>
/// Unregisters a specified type and its parser.
/// </summary>
/// <typeparam name="T">The type to unregister.</typeparam>
/// <returns>True if a value is removed; otherwise, false.</returns>
public static bool UnsetParser<T>() => TypeParsers.Remove(typeof(T));
        
/// <summary>
/// Unregisters a specified type and its parser.
/// </summary>
/// <param name="type">The type ot unregister.</param>
/// <returns>True if a value is removed; otherwise, false.</returns>
public static bool UnsetParser(Type type) => TypeParsers.Remove(type);```
1 Like