Reputation: 27615
I am implementing a variation of the Command
design pattern. I have an abstract CodedCommand
class with some subclasses, each of one with an overriden "Code" property of type char
. Each subclass has then the responsibility to "encapsulate" its own Code
letter to which it is associated.
The use case is: when some serial parser receive a char/byte, I want to create an instance of the appropriate subclass, to further process the command payload.
My problem is: I don't know how to get the specific value from each subclass.
My current implementation is below. The problem, highlighted with a comment, is that type.GetProperty("Code")
is returning null!
internal abstract class CodedCommand
{
internal abstract char Code { get; }
}
internal class EventA : CodedCommand
{
internal override char Code => 'A';
}
internal class EventB : CodedCommand
{
internal override char Code => 'B';
}
public class CommandCreator
{
Dictionary<char, Type> _typeMap
= new Dictionary<char, Type>();
public CommandCreator()
{
var types = GetType().Assembly.GetTypes()
.Where(type => type.IsSubclassOf(typeof(CodedCommand)))
.Where(type => !type.IsAbstract);
foreach (var type in types)
{
var field = type.GetProperty("Code"); // returns null!!!
var value = field.GetValue(null);
var code = (char)value;
_typeMap[code] = type;
}
}
CodedCommand BuildCommand(char code)
{
_typeMap.TryGetValue(code, out Type type);
if (type != null)
{
return (CodedCommand)(Activator.CreateInstance(type));
}
return null;
}
}
So my question is how can I fix this design?
Upvotes: 3
Views: 182
Reputation: 62498
The problem is your property is marked as internal
, not public
and we cannot access the non-public properties using the overload which you are using.
You need to specify the flags
parmeter by using this overload if you want properties other than public
like:
type.GetProperty("Code",BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public)
Searches for the public property with the specified name.
GetProperty(string name,BindingFlags bindingAttr)
overload:
Searches for the specified property, using the specified binding constraints.
Upvotes: 1
Reputation: 3009
Here is complete solution for getting value of property:
var types = GetType().Assembly.GetTypes()
.Where(type => type.IsSubclassOf(typeof(CodedCommand)) && !type.IsAbstract);
foreach (var type in types)
{
var obj = Activator.CreateInstance(type);
var field = type.GetProperty("Code", BindingFlags.Instance | BindingFlags.NonPublic);
var value = field.GetValue(obj);
var code = (char)value;
_typeMap[code] = type;
}
Please note that field.GetValue
needs object instance to work and NonPublic
-BindingFlag is needed when getting PropertyInformation for internal property.
Upvotes: 3