-1

I have several classes that derive from an abstract class. I'd like to be able to choose one of these derived classes based on the value of an abstract static property (say "maxSpeed") and create an instance of it. e.g., If my required speed is 5 and ClassA.maxSpeed is 2 and ClassB.maxSpeed is 7, client code would create and instance of Class B.

C# doesn't support inheritance of static properties and methods so the above scheme won't work. Is there a workaround?

user1899931
  • 107
  • 6
  • 4
    So you want a solution that chooses the class based on a property's value? This kind of seems like an X/Y problem to me. If we knew more about the problem you're trying to solve, we could probably suggest a better solution. – itsme86 Aug 17 '20 at 15:02
  • as @itsme86 said this sound like an [XY Problem](https://en.wikipedia.org/wiki/XY_problem). Your problem seems like you need a collection of some sort and use clone/copy or need class attributes and reflection or factory pattern – Franck Aug 17 '20 at 15:11
  • Consider using the [abstract factory pattern](https://en.wikipedia.org/wiki/Abstract_factory_pattern) or maybe the [builder pattern with inheritance](https://stackoverflow.com/q/244772). – dbc Aug 17 '20 at 18:00
  • FYI, interfaces in [C# 8.0](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8) will include support for [static members/methods, default implementations, and other goodies](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface). It's limited to using .NET Core 3.x runtimes, though. – Sean Skelly Aug 18 '20 at 19:49

2 Answers2

0

You can use custom attributes:

using System;
using System.Linq;
using System.Reflection;

namespace ConsoleApp10
{

    abstract class Abstract {}

    [MaxSpeed(10)]
    class ClassA : Abstract {}

    [MaxSpeed(20)]
    class ClassB : Abstract {}

    internal class MaxSpeedAttribute : Attribute
    {
        public int MaxSpeed { get; }

        public MaxSpeedAttribute(int maxSpeed)
        {
            MaxSpeed = maxSpeed;
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            var candidates = Assembly
                .GetExecutingAssembly()
                .GetTypes()
                .Where(t => t.IsSubclassOf(typeof(Abstract)))
                .Select(t => (type: t, maxSpeedAtt: t.GetCustomAttribute<MaxSpeedAttribute>()))
                .Where(t => t.maxSpeedAtt != null);

            var candidate = candidates.FirstOrDefault(c => c.maxSpeedAtt.MaxSpeed > 4);
            var myClass = (Abstract)Activator.CreateInstance(candidate.type);
        }
    }
}


enter image description here

Note This will fail if the class does not have a parameterless constructor. It will also fail if no classes that extend Abstract declare the attribute.

Also bear in mind if your classes are in other assemblies you will need to scan those instead of Assembly.GetExecutingAssembly().GetTypes()

I will leave it up to you to come up with the selection logic that you desire.

Jason
  • 1,505
  • 5
  • 9
0

Thank you for the responses. I've decided to change (what should be) static properties to non-static and create an instance of the class when I need to determine "maxSpeed." So, instead of "ClassA.maxSpeed" it's "new ClassA().maxSpeed".

user1899931
  • 107
  • 6