-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStrategy.cs
114 lines (90 loc) · 3.1 KB
/
Strategy.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
using System.Reflection;
namespace strategy_by_reflection;
public enum StateIdentifier
{
None,
StateA,
StateB
}
public abstract class StateStrategy
{
public abstract void Execute();
}
public class StateStrategyA : StateStrategy
{
public static readonly StateIdentifier Identifier = StateIdentifier.StateA;
public override void Execute()
{
Console.WriteLine("Executing Strategy A");
}
}
public class StateStrategyB : StateStrategy
{
public static readonly StateIdentifier Identifier = StateIdentifier.StateB;
public override void Execute()
{
Console.WriteLine("Executing Strategy B");
}
}
public static class StateStrategyFactory
{
public static StateStrategy CreateInstance(StateIdentifier identifier)
{
if(identifier.Equals(StateIdentifier.None))
{
throw new ArgumentException("Use an identifier other than None");
}
var helper = new StrategyReflectionHelper();
var strategyTypes = helper.GetStrategyTypes();
var strategies = new Dictionary<StateIdentifier, Type>();
foreach(var strategyType in strategyTypes)
{
var strategyIdentifier = helper.GetSubClassIdentifier(strategyType);
if(strategies.ContainsKey(strategyIdentifier))
{
throw new ArgumentException($"{Enum.GetName(strategyIdentifier)} identifier found in {strategyType.Name} already exists in {strategies[identifier].Name}");
}
strategies[strategyIdentifier] = strategyType;
}
return (Activator.CreateInstance(strategies[identifier]) as StateStrategy)!;
throw new ArgumentException($"No StateStrategy found for identifier '{identifier}'");
}
}
public class StrategyReflectionHelper
{
public IReadOnlyList<Type> GetStrategyTypes()
{
return Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.IsSubclassOf(typeof(StateStrategy)))
.ToList();
}
public StateIdentifier GetSubClassIdentifier(Type subClass)
{
var field = GetIdentifierField(subClass);
var value = field.GetValue(null);
if(value is null)
{
throw new NullReferenceException($"{subClass.Name} Identifier value cannot be null");
}
if(value.GetType() != typeof(StateIdentifier))
{
throw new ArgumentException($"{subClass.Name} Identifier should be {nameof(StateIdentifier)} enum type");
}
var identifier = (StateIdentifier)value;
if(identifier == StateIdentifier.None)
{
throw new ArgumentException($"{subClass.Name} Identifier must use a value other than {nameof(StateIdentifier.None)}");
}
return (StateIdentifier)value!;
}
private FieldInfo GetIdentifierField(Type subClass)
{
var field = subClass.GetField("Identifier", BindingFlags.Public | BindingFlags.Static);
if(field is null)
{
throw new InvalidOperationException($"{subClass.Name} does not have an Identifier field");
}
return field;
}
}