Dynamically create static fields C#?

Viewed 365

Is it possible to dynamically create static fields in a class?

class Pages
{
    private static T getPages<T>() where T : new()
    {
        var page = new T();
        PageFactory.InitElements(Browsers.getDriver, page);
        return page;
    }
    public static HomePage Home => getPages<HomePage>();
    public static DashboardPage Dashboard => getPages<DashboardPage>();
    public static ProfilePage Profile => getPages<ProfilePage>();
}

Right now I'm adding them one by one myself. Is there a way to dynamically add them? HomePage, DashboardPage and ProfilePage live under MyProject.Pages namespace, if I know how to dynamically create the static fields, I could loop through that namespace and dynamically create them.

2 Answers

What you ask isn't possible, as compiled code depends on the source it was compiled from. So unless you generate your sources dynamically (you could research T4 or T5 for that), a compiled class can not be extended in the way you describe.

However with a slightly different setup, the need for all this might become small or even absent. By making class Pages static, and then using it as follows: using static <namespace>.Pages, you can use its methods without prefixing them with the class name.

Full example (and accompanying .NET Fiddle):

using System;
using Project;
using static Project.Pages;

public class Program
{
    public static void Main()
    {
        var home = GetPage<Home>();
        var dashboard = GetPage<Dashboard>();
        var profile = GetPage<Profile>();

        Console.WriteLine(home.GetType().Name);
        Console.WriteLine(dashboard.GetType().Name);
        Console.WriteLine(profile.GetType().Name);
    }
}

namespace Project
{
    public static class Pages
    {
        public static T GetPage<T>() where T : new()
        {
            var page = new T();
            // ...
            return page;
        }
    }

    public class Home { /* ... */ }

    public class Dashboard { /* ... */ }

    public class Profile { /* ... */ }
}

You can then make it more compile-safe by making all Page classes implement an IPage interface, and adding a where T: IPage constraint to GetPage<T>().

Rather than adding properties, i would probably be easier if all those pages inherit from a common base class, and make a dictionary with a string as key. this way, you could easily add pages dynamically, without having to rely on generics.

public static pages = new Dictionary<string, IPage>{
   {"homepage", GetPages<HomePage>()},
   ...
}

or something like that, you probably don't even need a dictionary, you could do it with a list.

Even better would be to use an IOC container, and add a servicecollection extension to register all types that inherit from IPage. that way, you could just inject those pages wherever you need them, and it will register them automatically.

Related