Generating Classes and Dependencies Dynamically in C#

88 views Asked by At

I am bit new to C# and some of its advanced OOP features.

I am using the Bogus package to generate synthetic data.

Below is a sample code that picks a random value from the parameter list (EventActionsDomainValues) and assigns it to an attribute in a class (EventSchema) using the synthetic data generation rule defined for this attribute in syntheticEvent object.

However, I need to make this code fully parameterized as follows:

  1. The attribute name (EventAction) for class EventSchema cannot be hard coded. It needs to be read from some string parameter.
public class EventSchema
{
    public string? EventAction { get; set; }

    public override string ToString()
    {
        return $"{EventAction} ";
    }
}
  1. The attribute name (EventAction) and random values input (EventActionsDomainValues) into the synthetic data generation rule cannot be hard coded. They need to be read from some rule string parameters.
var syntheticEvent = syntheticEventFaker
        .RuleFor(de => de.EventAction, f => f.PickRandom(EventActionsDomainValues))
        .Generate();

Current code with hard coded classes:

using Bogus;

public class StaticClasses
{
    public static void Main()
    {
        // EventActionsDomainValues parameter.
        List<string> EventActionsDomainValues = new List<string>
        {
            "Post", "Patch", "Put", "Get", "Delete"
        };

        var syntheticEventFaker = new Faker<EventSchema>();

        var syntheticEvent = syntheticEventFaker
                .RuleFor(de => de.EventAction, f => f.PickRandom(EventActionsDomainValues))
                .Generate();

        Console.WriteLine(syntheticEvent.ToString());
    }
    public class EventSchema
    {
        public string? EventAction { get; set; }

        public override string ToString()
        {
            return $"{EventAction} ";
        }
    }
}

Need help/guidance with points 1 and 2 above. How would the parameterized code look?

1

There are 1 answers

0
jarmanso7 On

You can generate dynamic members and add and remove them at runtime with the ExpandoObject Class. For example:

internal class Program
{
    static dynamic CreateDynamicObject()
    {
        return new ExpandoObject();
    }

    static void AddPropertyDynamically(ExpandoObject expandoObject, string propertyName, object propertyValue )
    {
        var dictionary = expandoObject as IDictionary<string, object>;
        dictionary.Add(propertyName, propertyValue);
    }

    static void AddMethodDynamically(ExpandoObject expandoObject, string methodName, Func<object> methodValue)
    {
        var dictionary = expandoObject as IDictionary<string, object>;
        dictionary.Add(methodName, methodValue);
    }
    static void Main(string[] args)
    {
        // Create an object with a string property "EventAction"
        // and a method "ToString()"
        var eventSchema = CreateDynamicObject();

        AddPropertyDynamically(eventSchema, "EventAction", "");

        AddMethodDynamically(
            eventSchema,
            "ToString",
            new Func<object>(() =>
            {
                var dictionary = eventSchema as IDictionary<string, object>;
                return (string)dictionary["EventAction"];
            }));

        try
        {
            // Test members for our first object
            eventSchema.EventAction = "This is an EventAction";

            Console.WriteLine(eventSchema.EventAction); // Output: This is an EvenAction

            // Throws an exception if we try to access
            // a non existing member
            eventSchema.NonExistingMethod();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message); // Output: 'System.Dynamic.ExpandoObject' does not contain a definition for 'NonExistingMethod'
        }

        // Create a second object with a decimal property "Balance"ยท
        // and a method "Withdraw"

        var bankAccount = CreateDynamicObject();

        AddPropertyDynamically(bankAccount, "Balance", 1000.00M);

        AddMethodDynamically(
            bankAccount,
            "Withdraw",
            new Func<object>(() =>
            {
                var dictionary = bankAccount as IDictionary<string, object>;
                dictionary["Balance"] = (decimal)dictionary["Balance"] - 50.00M;

                return (decimal)dictionary["Balance"];
            }));


        // Test members for our second object
        Console.WriteLine($"Current balance = {bankAccount.Balance}"); // Output: Current balance = 1000.00

        var cash = (decimal)bankAccount.Withdraw();

        Console.WriteLine($"Current balance = {bankAccount.Balance}"); // Output: Current balance = 950.00

        Console.ReadLine();
    }
}