My question is best illustrated with an example.
Suppose I have the enum:
public enum ArrowDirection
{
North,
South,
East,
West
}
I want to associate the unit vector corresponding to each direction with that direction. For example I want something that will return (0, 1) for North, (-1, 0) for West, etc. I know in Java you could declare a method inside the enum which could provide that functionality.
My current solution is to have a static method -- inside the class that defines the enum -- that returns a vector corresponding to the passed in ArrowDirection (the method uses a HashTable to accomplish the lookup but that's not really important). This seems... unclean.
Question:
Is there a best-practice solution for storing additional information corresponding to an enum in .NET?
There's a FANTASTIC new way to do this in C# 3.0. The key is this beautiful fact: Enums can have extension methods! So, here's what you can do:
public enum ArrowDirection
{
North,
South,
East,
West
}
public static class ArrowDirectionExtensions
{
public static UnitVector UnitVector(this ArrowDirection self)
{
// Replace this with a dictionary or whatever you want ... you get the idea
switch(self)
{
case ArrowDirection.North:
return new UnitVector(0, 1);
case ArrowDirection.South:
return new UnitVector(0, -1);
case ArrowDirection.East:
return new UnitVector(1, 0);
case ArrowDirection.West:
return new UnitVector(-1, 0);
default:
return null;
}
}
}
Now, you can do this:
var unitVector = ArrowDirection.North.UnitVector();
Sweet! I only found this out about a month ago, but it is a very nice consequence of the new C# 3.0 features.
Here's another example on my blog.
I've blogged about it here.
Try out something like this with Attributes.
public enum Status {
[Status(Description = "Not Available")]
Not_Available = 1,
[Status(Description = "Available For Game")]
Available_For_Game = 2,
[Status(Description = "Available For Discussion")]
Available_For_Discussion = 3,
}
public class StatusEnumInfo {
private static StatusAttribute[] edesc;
public static String GetDescription(object e)
{
System.Reflection.FieldInfo f = e.GetType().GetField(e.ToString());
StatusEnumInfo.edesc = f.GetCustomAttributes(typeof(StatusAttribute), false) as StatusAttribute[];
if (StatusEnumInfo.edesc != null && StatusEnumInfo.edesc.Length == 1)
return StatusEnumInfo.edesc[0].Description;
else
return String.Empty;
}
public static object GetEnumFromDesc(Type t, string desc)
{
Array x = Enum.GetValues(t);
foreach (object o in x) {
if (GetDescription(o).Equals(desc)) {
return o;
}
} return String.Empty;
}
}
public class StatusAttribute : Attribute {
public String Description { get; set; }
}
public class Implemenation {
public void Run()
{
Status statusEnum = (Status)StatusEnumInfo.GetEnumFromDesc(typeof(Status), "Not Available");
String statusString = StatusEnumInfo.GetDescription(Status.Available_For_Discussion);
}
}
Instead of Description, use your custom Property
using System.ComponentModel;
using System.Reflection;
public enum ArrowDirection
{
[Description("Northwards")]
North,
[Description("Southwards")]
South,
[Description("Eastwards")]
East,
[Description("Westwards")]
West
}
...
Create an extension method to get a list of descriptions:
public static class Enum<T> where T : struct
{
/// <summary>
/// Gets a collection of the enum value descriptions.
/// </summary>
/// <returns></returns>
public static IList<string> GetDescriptions()
{
List<string> descriptions = new List<string>();
foreach (object enumValue in Enum<T>.GetValues())
{
descriptions.Add(((Enum)enumValue).ToDescription());
}
return descriptions;
}
}
One thing you could look at is the "Type-Safe Enum" pattern. This allows you to create an enum that is actually a full-fledged static object, which can have methods/properties/etc..
http://www.javacamp.org/designPattern/enum.html
Joshua Bloch talks about this pattern in his book "Effective Java." I've used it in a lot of different situations, and I actually prefer it over plain enums. (It's language-agnostic - it works in Java, C#, or pretty much any OO language).
Your static method approach seems quite clean to me. You encapsulate both the enum and the static method within the same class. Changes to the enum are centralised within that single class.
Adding a method to the enumeration (as per Java) seems to add complexity to something that is really a very simple concept.
The attribute based approach is interesting, but once again seems to overcomplicate things when compared to a static method.
Related
I want to create a structure to store data consumed from a Web Service with the followind specs:
Response:
Field 1 - InstructionType: Can be 1 (PreferredDay), 2 (SVP), 3 (Neighbour)
Field 2: Some variable data. Its type depends on Field 1. So if:
Field 1 == 1 then Field 2 type will be of DateTime (dd.MM.yyyy)
Field 1 == 2 then Field 2 type will be of type string.
Field 1 == 3 then Field 2 type will be of type string
So, I started up with the following enum:
public enum InstructionType
{
None = 0,
PreferredDay = 1,
ServicePoint = 2,
Neighbour = 3
}
And the generic class:
public abstract class Instruction<T>
{
public InstructionType Type { get; private set; }
public T Data { get; private set; }
public Instruction(InstructionType type, T data)
{
this.Type = type;
this.Data = data;
}
}
and concrete classes:
public class PreferredDayInstruction : Instruction<DateTime>
{
public PreferredDayInstruction(DateTime data)
: base (InstructionType.PreferredDay, data) {}
}
public class ServicePointInstruction: Instruction<string>
{
public ServicePointInstruction(string data)
: base (InstructionType.ServicePoint, data) {}
}
public class NeughbourInstruction: Instruction<string>
{
public NeughbourInstruction(string data)
: base (InstructionType.Neighbour, data) {}
}
When parsing web service's response created a public function:
public Instruction DeliveryInstruction() <---Compiler error here "Instruction"
{
if (resultFromWebservice.Field1 == 1)
return new PreferredDayInstruction((DateTime)Field2);
if (resultFromWebservice.Field1 == 2)
return new ServicePointInstruction(Field2);
if (resultFromWebservice.Field1 == 3)
return new NeighbourInstruction(Field2);
}
and here is the problem. Can't return objects of generic type.
Tried with with Interface, factories, and other stuff, but allways with the same problem. So, is there any way to archieve this? maybe it's not possible or maybe is so easy I can't see now. Thanks in advance.
UPDATE:
Compiler error on BOLD Instruction
Error 1 Using the generic type 'NAMESPACE.Instruction' requires '1' type arguments
I forgot..I'm using .NET 3.5
It looks like you may be starting off with an intent to use generics rather than using them because you've identified a need. Often (not always) when that gets difficult it's because it didn't actually fit what you were trying to do.
What seems odd in this case is that you have both a generic type and an enum to indicate the type. This is likely to cause you a few problems.
First it looks like you're trying to create a one-size-fits all class to model different types of behaviors. That will start off confusing and get more confusing. Think of most classes that are part of the .NET framework, and imagine what would happen if they had properties like Field1 and Field2, and you couldn't tell from looking at them what they were for. And in one method they're used for one thing, but in a another case they mean something else.
Also, if you're trying to put different types of instructions in one class, that suggests that maybe you're going to try passing them all to one method, and that method figures out what to do, and maybe calls other methods. (I'm guessing that because of the enum. Perhaps you're going to handle the input differently depending on which value it contains.) That one method will get really hard to maintain.
I'd recommend waiting on generics until you're sure you need them. And if you have different types of instructions you're likely better off writing a different class for each one with the properties it needs and names that describe them, and writing methods for each of them to do what they need to do. If you need lots of classes, make lots of them.
It's very easy to fall into the trap of trying to solve problems that don't exist, like how do I write one class that covers a bunch of different needs. The answer usually that you don't need to. You'll get better results from writing more classes that each do fewer things.
Believe me that I tried to do my best to explain what was my problem and what I needed in order to solve it. In a nutshell, the question was quite simple. Is this possible or not? So, is there a way to return a common type for these 3 classes? Answer is no, as they don't share any root. They all derive from Instruction, but aren't compatible each other. That's what I learned from this experience.
As another example, lets take another .NET framework's generic type.
public class ListOfString : List<string> { }
public class ListOfInt : List<int> { }
public class ListOfDecimal : List<decimal> { }
And, in another place of the application, get a method who returns one of this List based on some logic:
public class Logic
{
public List<> GetList(Type t) <----This can't be done
{
if (t == typeof(string))
return new ListOfString();
if (t == typeof(int))
return new ListOfInt();
if (t == typeof(decimal))
return new ListOfDecimal();
else return null;
}
}
Please, keep in mind that this is just a stupid sample just to show what's the point of this post.
By the way, in the case of List the following can be done, because there is a non generic different version of IList:
public IList GetList(Type t)
{
....
}
But I can't think of a way to do this in my particular case.
Anyway, I finally followed another approach. I reallized that what I really wanted is to ensure Data property is valid. If it it's supposed to be a date there, ensure date is valid. Is it a string, ensure it has the right length or whatever rule it must follow.
So this is the final solution:
The enum:
public enum InstructionType
{
None = 0,
PreferredDay = 1,
ServicePoint = 2,
Neighbour = 3
}
The base class:
public abstract class Instruction
{
public InstructionType Type { get; private set; }
public string Data { get; private set; } <---Type String
public Instruction(InstructionType type, string data)
{
this.Type = type;
this.Data = IsValid(data) ? data : string.Empty;
}
public abstract bool IsValid(string data); <--the rule.
}
The concrete classes:
public class PreferredDayInstruction : Instruction
{
public PreferredDayInstruction(string date)
: base(InstructionType.PreferredDay, date) { }
public override bool IsValid(string data)
{
string[] formats = {"dd.MM.yyyy", "d.MM.yyyy",
"dd.MM.yy", "d.MM.yy"};
try
{
data = data.Replace('/', '.').Replace('-', '.');
var dateparts = data.Split('.');
DateTime date = new DateTime(Convert.ToInt32(dateparts[2]),
Convert.ToInt32(dateparts[1]),
Convert.ToInt32(dateparts[0]));
//DateTime.ParseExact(data, formats, null, System.Globalization.DateTimeStyles.AssumeLocal);
return true;
}
catch (Exception)
{
return false;
}
}
}
public class ServicePointInstruction : Instruction
{
public ServicePointInstruction(string data)
: base (InstructionType.ServicePoint, data) { }
public override bool IsValid(string data)
{
return ServicePointBarcodeValidator.Validate(data);
}
}
public class NeighbourInstruction : Instruction
{
public NeighbourInstruction(string data) :
base(InstructionType.Neighbour, data) { }
public override bool IsValid(string data)
{
return data.Length <= 70;
}
}
A factory class, who's responsability is to create and return the correct object based on the enum:
public static class DeliveryInstructionFactory
{
public static Instruction Create(int type, string data)
{
return Create((InstructionType)type, data);
}
public static Instruction Create(InstructionType type, string data)
{
switch (type)
{
case InstructionType.PreferredDay:
return new PreferredDayInstruction(data);
case InstructionType.ServicePoint:
return new ServicePointInstruction(data);
case InstructionType.Neighbour:
return new NeighbourInstruction(data);
default:
return null;
}
}
}
And finally, as now all of they share the same root, object can be created on webservice's response parser:
public Instruction DeliveryInstruction()
{
try
{
int instructionCode = int.Parse(observation.Substring(173,2));
string instructionData = observation.Substring(175, 10);
return DeliveryInstructionFactory.Create(instructionCode, instructionData); }
catch (Exception ex)
{
Log.Error("[ValidationBarcodeResponse] DeliveryInstructions aren't in the correct format", ex);
return null;
}
}
Hope this now fits on a Minimal, Complete, and Verifiable example
I have a class wherein I want to use Strings with a fixed size.
The reason for the fixed size is that the class "serializes" into a textfile
with values with a fixed length. I want to avoid to write foreach value a guard clause and instead have the class handle this.
So I have round about 30 properties which would look like this
public String CompanyNumber
{
get
{
return m_CompanyNumber.PadLeft(5, ' ');
}
set
{
if (value.Length > 5)
{
throw new StringToLongException("The CompanyNumber may only have 5 characters", "CompanyNumber");
}
m_CompanyNumber = value;
}
}
I would like to have a String that handles this by itself. Currently I have the following:
public class FixedString
{
String m_FixedString;
public FixedString(String value)
{
if (value.Length > 5)
{
throw new StringToLongException("The FixedString value may consist of 5 characters", "value");
}
m_FixedString= value;
}
public static implicit operator FixedString(String value)
{
FixedString fsv = new FixedString(value);
return fsv;
}
public override string ToString()
{
return m_FixedString.PadLeft(5,' ');
}
}
The problem I have with this solution is that I can't set the String length at "compile time".
It would be ideal if it would look something like this in the end
public FixedString<5> CompanyNumber { get; set; }
I would go further back and question the design. This solution mashes together two concerns--internal application state and storage format--that should remain separate.
You could decorate each string property with a MaxLengthAttribute and then validate to that, but your code for (de)serializing from your storage format should be completely separate. It could use the same attributes to glean the field lengths for storage (if that happy coincidence holds) but your internal representation shouldn't "know" about the storage details.
Make FixedString take the size as a constructor parameter, but not the value itself
public class FixedString
{
private string value;
private int length;
public FixedString(int length)
{
this.length = length;
}
public string Value
{
get{ return value; }
set
{
if (value.Length > length)
{
throw new StringToLongException("The field may only have " + length + " characters");
}
this.value = value;
}
}
}
Initilise it with your class, and just set the Value when it changes
public class MyClass
{
private FixedString companyNumber = new FixedString(5);
public string CompanyNumber
{
get{ return companyNumber.Value; }
set{ companyNumber.Value = value; }
}
}
You can define an Interface like this:
public interface ILength
{
int Value { get; }
}
Some struct that implements the interface:
public struct LengthOf5 : ILength
{
public int Value { get { return 5; } }
}
public struct LengthOf10 : ILength
{
public int Value { get { return 10; } }
}
And then:
public class FixedString<T> where T : struct, ILength
{
String m_FixedString;
public FixedString(String value)
{
if (value.Length > default(T).Value)
{
throw new ArgumentException("The FixedString value may consist of " + default(T).Value + " characters", "value");
}
m_FixedString = value;
}
public static implicit operator FixedString<T>(String value)
{
FixedString<T> fsv = new FixedString<T>(value);
return fsv;
}
public override string ToString()
{
return m_FixedString;
}
}
To be honest I don't know if i like this solution but is the best I can think to solve your problem.
You could put an attribute over your String property and then validate all of them at some time (maybe a button click or something like that).
using System.ComponentModel.DataAnnotations;
public class MyObject
{
[StringLength(5)]
public String CompanyName { get; set; }
}
public void Save(MyObject myObject)
{
List<ValidationResult> results = new List<ValidationResult>();
ValidationContext context = new ValidationContext(myObject, null, null);
bool isValid = Validator.TryValidateObject(myObject, context, results);
if (!isValid)
{
foreach (ValidationResult result in results)
{
// Do something
}
}
}
More about DataAnnotations here.
I think your original idea of creating a string of fixed length is a very valid one, strictly modelling the domain of your system and using the type system to verify it is an idea that I find very appealing. Questions like this seem to come up very often within the F# community.
Unfortunately something like the type definition you suggested (FixedString<5>) is not possible in the context of .NET.
Some of the answers so far have talked about workarounds, alternatives or other ideas, I'd like to instead answer why you can't do what you originally requested in C#.
First of all, lets look at how you could do this in an arbitrary language:
Templates: You could do something like this in C++ using the template system. As Eric Lippert puts it in his article on the differences between generics and templates, "You can think of templates as a fancy-pants search-and-replace mechanism" (https://blogs.msdn.microsoft.com/ericlippert/2009/07/30/whats-the-difference-part-one-generics-are-not-templates/).
.NET generics are, in many ways, far simpler by comparison. Generic types are allow you to parametrise over types but not over values and open types are resolved at runtime whereas templates are an entirely compile time construct.
Dependent Types: A few languages support a feature called dependent types (https://en.wikipedia.org/wiki/Dependent_type). This allows you to define types that depend upon values. Many languages that support this feature are geared toward theorem proving rather than general purpose development.
Idris is perhaps unusual in being a general purpose language under active development (albeit a little known one) which does support this feature (see http://www.idris-lang.org/).
C#
C# does not support either of these features so, unfortunately, you can't solve this problem in a way that can be rigorously verified by the compiler.
I think there are plenty of good suggestions covered here for how you might implement something like this in C# but they all boil down to run-time verification.
I'm trying to implement a simple plugin system which will allow people to write the following:
[Plugin("A plugin function")]
public static int PluginFunction(int a, int b)
{
return a + b;
}
and then drop the DLL containing this function into a folder where it will be scanned by the application and show up as an available function at runtime. This all works fine, so far so good, the PluginAttribute class is what you would expect, just a description string for the function.
However, I'd like to allow the plugin writer to specify default values for the parameters. This is OK for values which are constant at compile time and then deduced via reflection, but I'd like a way to specify defaults for more complex types which will be created at runtime. Has anyone implemented something similar? The primary goal is to make it simple to implement plugin functions - I'm trying to avoid complex scaffolding but accept that my nice simple system is not going to cut it if I want this feature. I'm also happy to have some complexity in the application code which makes the system appear simple to the plugin writer.
Thanks,
Charlie.
Update:
I'm going with a combination of what's been suggested here, the closest is what Peter O. came up with - here's a version:
[Plugin("A plugin function")]
[Defaults(typeof(AdderDefaults))]
public static int Adder(int a, int b)
{
return a + b;
}
public static class AdderDefaults
{
public static int a { get { return 1; } }
public static int b { get { return 2; } }
}
[Plugin("Another plugin function")]
[Defaults(typeof(TexturizerDefaults))]
public static Bitmap Texturize(Bitmap source, Point offset)
{
return result;
}
public static class TexturizerDefaults
{
// no default for source parameter
public static Point offset { get { return new Point(16, 16); } }
}
This allows parameters to be skipped and specified by name. No compile time checking but that's OK - checking these at runtime is acceptable.
Maybe you can create an attribute which refers to a type
containing default values for the plugin. Example:
[PluginDefaults(typeof(MyPluginDefaults))]
The class MyPluginDefaults could then look like:
public class MyPluginDefaults {
int Parameter1 { // First parameter
get { return 0; } // default value for 'a'
}
int Parameter2 { // Second parameter
get { return 4; } // default value for 'b'
}
// Additional parameters would be called Parameter3, Parameter4, and so on.
}
There are lots of way to do that, the simpliest is to use a simple convention :
[Plugin("A plugin function")]
public static int PluginFunction(int a, int b)
{
return a + b;
}
public static object[] PluginFunctionDefaultArguments()
{
return new [] { 0, 0 };
}
Each time you find a function marked with PluginAttribute search for a function having the same name with the DefaultArguments sufix, no parameters and an object[] return type. Then call it and store the values somewhere. You should also support the default values to be specifed using the dedicated C#/VB syntax (it is found in the DefaultValue member for the parameter)
One way would be to have property Defaults for each of the classes. It returns an object that can be queried for the defaults, for example like this:
object[] pluginFunctionDefaults = FooPlugin.Defaults["PluginFunction"];
(Obviously, you wouldn't have code exactly like this in your application.)
And the declaration of the defaults could look like this:
class FooPlugin
{
static FooPlugin()
{
var bar = new Bar();
Defaults = new DefaultValues()
.Add(() => PluginFunction(42, 13))
.Add(() => AnotherFunction(bar));
}
public static DefaultValues Defaults { get; private set; }
// actual methods of the class
}
Using expressions like this means that the types of the defaults are checked at compile time. The DefaultValues class parses the expressions and stores the parameters. It could look something like this:
class DefaultValues
{
private readonly Dictionary<string, object[]> m_expressions =
new Dictionary<string, object[]>();
public DefaultValues Add<T>(Expression<Func<T>> func)
{
var methodCall = ((MethodCallExpression)func.Body);
var name = methodCall.Method.Name;
var arguments =
methodCall.Arguments
.Select(Evaluate)
.ToArray();
m_expressions.Add(name, arguments);
return this;
}
private static object Evaluate(Expression expression)
{
return Expression.Lambda<Func<object>>(
Expression.Convert(expression, typeof(object)))
.Compile()();
}
public object[] this[string methodName]
{
get { return m_expressions[methodName]; }
}
}
This is related to a prior question of mine C# Generic List conversion to Class implementing List<T>
I have the following code:
public abstract class DataField
{
public string Name { get; set; }
}
public class DataField<T> : DataField
{
public T Value { get; set; }
}
public static List<DataField> ConvertXML(XMLDocument data) {
result = (from d in XDocument.Parse(data.OuterXML).Root.Decendendants()
select new DataField<string>
{
Name = d.Name.ToString(),
Value = d.Value
}).Cast<DataField>().ToList();
return result;
}
This works however I would like to be able to modify the select portion of the LINQ query to be something like this:
select new DataField<[type defined in attribute of XML Element]>
{
Name = d.Name.ToString(),
Value = d.Value
}
Is this just a poor approach? is it possible? Any suggestions?
Here is a working solution: (You must specify fully qualified type names for your Type attribute otherwise you have to configure a mapping somehow...)
I used the dynamic keyword, you can use reflection to set the value instead if you do not have C# 4...
public static void Test()
{
string xmlData = "<root><Name1 Type=\"System.String\">Value1</Name1><Name2 Type=\"System.Int32\">324</Name2></root>";
List<DataField> dataFieldList = DataField.ConvertXML(xmlData);
Debug.Assert(dataFieldList.Count == 2);
Debug.Assert(dataFieldList[0].GetType() == typeof(DataField<string>));
Debug.Assert(dataFieldList[1].GetType() == typeof(DataField<int>));
}
public abstract class DataField
{
public string Name { get; set; }
/// <summary>
/// Instanciate a generic DataField<T> given an XElement
/// </summary>
public static DataField CreateDataField(XElement element)
{
//Determine the type of element we deal with
string elementTypeName = element.Attribute("Type").Value;
Type elementType = Type.GetType(elementTypeName);
//Instanciate a new Generic element of type: DataField<T>
dynamic dataField = Activator.CreateInstance(typeof(DataField<>).MakeGenericType(elementType));
dataField.Name = element.Name.ToString();
//Convert the inner value to the target element type
dynamic value = Convert.ChangeType(element.Value, elementType);
//Set the value into DataField
dataField.Value = value;
return dataField;
}
/// <summary>
/// Take all the descendant of the root node and creates a DataField for each
/// </summary>
public static List<DataField> ConvertXML(string xmlData)
{
var result = (from d in XDocument.Parse(xmlData).Root.DescendantNodes().OfType<XElement>()
select CreateDataField(d)).ToList();
return result;
}
}
public class DataField<T> : DataField
{
public T Value { get; set; }
}
You cannot do this easily in C#. The generic type argument has to specified at compile time. You can use reflection to do otherwise
int X = 1;
Type listype = typeof(List<>);
Type constructed = listype.MakeGenericType( X.GetType() );
object runtimeList = Activator.CreateInstance(constructed);
Here we have just created a List<int>. You can do it with your type
Different instances of a generic class are actually different classes.
I.e. DataField<string> and DataField<int> are not the same class at all(!)
This means, that you can not define the generic parameter during run-time, as it has to be determined during compile-time.
I would say this is a poor approach. In reality, even after you parse your XML file, you're not going to know what types of "DataFields" you have. You might as well just parse them as objects.
However, if you know that you're only ever going to have x number of types, you can do like so:
var Dictionary<string, Func<string, string, DataField>> myFactoryMaps =
{
{"Type1", (name, value) => { return new DataField<Type1>(name, Type1.Parse(value); } },
{"Type2", (name, value) => { return new DataField<Type2>(name, Type2.Parse(value); } },
};
Termit's answer is certainly excellent. Here is a little variant.
public abstract class DataField
{
public string Name { get; set; }
}
public class DataField<T> : DataField
{
public T Value { get; set; }
public Type GenericType { get { return this.Value.GetType(); } }
}
static Func<XElement , DataField> dfSelector = new Func<XElement , DataField>( e =>
{
string strType = e.Attribute( "type" ).Value;
//if you dont have an attribute type, you could call an extension method to figure out the type (with regex patterns)
//that would only work for struct
Type type = Type.GetType( strType );
dynamic df = Activator.CreateInstance( typeof( DataField<>).MakeGenericType( type ) );
df.Name = e.Attribute( "name" ).Value;
dynamic value = Convert.ChangeType( e.Value , type );
df.Value = value;
return df;
} );
public static List<DataField> ConvertXML( string xmlstring )
{
var result = XDocument.Parse( xmlstring )
.Root.Descendants("object")
.Select( dfSelector )
.ToList();
return result;
}
static void Main( string[] args )
{
string xml = "<root><object name=\"im1\" type=\"System.String\">HelloWorld!</object><object name=\"im2\" type=\"System.Int32\">324</object></root>";
List<DataField> dfs = ConvertXML( xml );
}
you can create generic type by reflection
var instance = Activator.CreateInstance( typeof(DataField)
.MakeGenericType(Type.GetType(typeNameFromAttribute) );
// and here set properties also by reflection
#Termit and #Burnzy put forward good solutions involving factory methods.
The problem with that is that you're loading up your parsing routine with a bunch of extra logic (more testing, more errors) for dubious returns.
Another way to do it would be to use a simplified string-based DataField with typed read methods - the top answer for this question.
An implementation of a typed-value method that would be nice but only works for value types (which does not include strings but does include DateTimes):
public T? TypedValue<T>()
where T : struct
{
try { return (T?) Convert.ChangeType(this.Value, typeof(T)); }
catch { return null; }
}
I'm assuming that you're wanting to use the type information to do things like dynamically assigning user-controls to the field, validation rules, correct SQL types for persistence etc.
I've done a lot of this sort of thing with approaches that seem a bit like yours.
At the end of the day you should seperate your metadata from your code - #Burnzy's answer chooses the code based on the metadata (a "type" attribute of the DataField element) and is a very simple example of this.
If you're dealing with XML, XSDs are a very useful and extensible form of metadata.
As far as what you store each field's data in - use strings because:
they are nullable
they can store partial values
they can store invalid values (makes telling the user to sort their act out more transparent)
they can store lists
special cases won't invade unrelated code because there aren't any
learn regular expressions, validate, be happy
you can convert them to stronger types really easily
I found it very rewarding to develop little frameworks like this - it is a learning experience and you'll come out understanding a lot more about UX and the reality of modelling from it.
There are four groups of test cases that I would advise you to tackle first:
Dates, Times, Timestamps (what I call DateTime), Periods (Timespan)
in particular, make sure you test having a different server locality from the client's.
lists - multi-select foreign keys etc
null values
invalid input - this generally involves retaining the original value
Using strings simplifies all this greatly because it allows you to clearly demarcate responsibilities within your framework. Think about doing fields containing lists in your generic model - it gets hairy rather quickly and it is easy to end up with a special case for lists in pretty much every method. With strings, the buck stops there.
Finally, if you want a solid implementation of this sort of stuff without having to do anything much, consider DataSets - old school I know - they do all sorts of wonderful things you wouldn't expect but you do have to RTFM.
The main downfall of that idea would be that it isn't compatible with WPF data binding - though my experience has been that reality isn't compatible with WPF data binding.
I hope I interpreted your intentions correctly - good luck either way :)
Unfortunately, there no inheritance relation between C<T> and C<string> for instance.
However, you can inherit from a common non-generic class and in addition to this implement a generic interface.
Here I use explicit interface implementation in order to be able to declare a Value property typed as object, as well as a more specifically typed Value property.
The Values are read-only and can only be assigned through a typed constructor parameter. My construction is not perfect, but type safe and doesn't use reflection.
public interface IValue<T>
{
T Value { get; }
}
public abstract class DataField
{
public DataField(string name, object value)
{
Name = name;
Value = value;
}
public string Name { get; private set; }
public object Value { get; private set; }
}
public class StringDataField : DataField, IValue<string>
{
public StringDataField(string name, string value)
: base(name, value)
{
}
string IValue<string>.Value
{
get { return (string)Value; }
}
}
public class IntDataField : DataField, IValue<int>
{
public IntDataField(string name, int value)
: base(name, value)
{
}
int IValue<int>.Value
{
get { return (int)Value; }
}
}
The list can then be declared with the abstract base class DataField as generic parameter:
var list = new List<DataField>();
switch (fieldType) {
case "string":
list.Add(new StringDataField("Item", "Apple"));
break;
case "int":
list.Add(new IntDataField("Count", 12));
break;
}
Access the strongly typed field through the interface:
public void ProcessDataField(DataField field)
{
var stringField = field as IValue<string>;
if (stringField != null) {
string s = stringField.Value;
}
}
While the other questions mostly proposed an elegant solution to convert your XML elements to a generic class instance, I'm going to deal with the consequences of taking the approach to model the DataField class as a generic like DataField<[type defined in attribute of XML Element]>.
After selecting your DataField instance into the list you want to use these fields. Her polymorphism comes into play! You want to iterate your DataFields an treat them in a uniform way. Solutions that use generics often end up in a weird switch/if orgy since there is no easy way to associate behavior based on the generic type in c#.
You might have seen code like this (I'm trying to calculate the sum of all numeric DataField instances)
var list = new List<DataField>()
{
new DataField<int>() {Name = "int", Value = 2},
new DataField<string>() {Name = "string", Value = "stringValue"},
new DataField<float>() {Name = "string", Value = 2f},
};
var sum = 0.0;
foreach (var dataField in list)
{
if (dataField.GetType().IsGenericType)
{
if (dataField.GetType().GetGenericArguments()[0] == typeof(int))
{
sum += ((DataField<int>) dataField).Value;
}
else if (dataField.GetType().GetGenericArguments()[0] == typeof(float))
{
sum += ((DataField<float>)dataField).Value;
}
// ..
}
}
This code is a complete mess!
Let's go try the polymorphic implementation with your generic type DataField and add some method Sum to it that accepts the old some and returns the (possibly modified) new sum:
public class DataField<T> : DataField
{
public T Value { get; set; }
public override double Sum(double sum)
{
if (typeof(T) == typeof(int))
{
return sum + (int)Value; // Cannot really cast here!
}
else if (typeof(T) == typeof(float))
{
return sum + (float)Value; // Cannot really cast here!
}
// ...
return sum;
}
}
You can imagine that your iteration code gets a lot clearer now but you still have this weird switch/if statement in you code. And here comes the point: Generics do not help you here it's the wrong tool at the wrong place. Generics are designed in C# for giving you compile time type safety to avoid potential unsafe cast operations. They additionally add to code readability but that's not the case here :)
Let's take a look at the polymorphic solution:
public abstract class DataField
{
public string Name { get; set; }
public object Value { get; set; }
public abstract double Sum(double sum);
}
public class IntDataField : DataField
{
public override double Sum(double sum)
{
return (int)Value + sum;
}
}
public class FloatDataField : DataField
{
public override double Sum(double sum)
{
return (float)Value + sum;
}
}
I guess you will not need too much fantasy to imagine how much adds to your code's readability/quality.
The last point is how to create instances of these classes. Simply by using some convention TypeName + "DataField" and Activator:
Activator.CreateInstance("assemblyName", typeName);
Short Version:
Generics is not the appropriate approach for your problem because it does not add value to the handling of DataField instances. With the polymorphic approach you can work easily with the instances of DataField!
It's not impossible as you can do this with reflection. But this isn't what generics were designed for and isn't how it should be done. If you're going to use reflection to make the generic type, you may as well not use a generic type at all and just use the following class:
public class DataField
{
public string Name { get; set; }
public object Value { get; set; }
}
You'll need to insert the logic for determining the data type from your XML and add all the types you need to use but this should work:
result = (from d in XDocument.Parse(data.OuterXML).Root.Descendants()
let isString = true //Replace true with your logic to determine if it is a string.
let isInt = false //Replace false with your logic to determine if it is an integer.
let stringValue = isString ? (DataField)new DataField<string>
{
Name = d.Name.ToString(),
Value = d.Value
} : null
let intValue = isInt ? (DataField)new DataField<int>
{
Name = d.Name.ToString(),
Value = Int32.Parse(d.Value)
} : null
select stringValue ?? intValue).ToList();
EDIT 1: Forgot to add the nested property curve ball.
UPDATE: I have chosen #mtazva's answer as that was the preferred solution for my specific case. In retrospect, I asked a general question with a very specific example and I believe that ended up confusing everyone (or maybe just me) as to what the question was exactly. I do believe the general question has been answered as well (see the Strategy pattern answers and links). Thanks everyone!
Large switch statements obviously smell and I have seen some links on how you could do this with a dictionary that maps to functions. But I'm wondering if there is a better (or smarter way) to do this? In a way, this is a question I've always sort of had rolling around in the back of my head but never really had a good solution to.
This question stemmed from another question I asked earlier: How to select all the values of an object's property on a list of typed objects in .Net with C#
Here is an example class I'm working with (from an external source):
public class NestedGameInfoObject
{
public string NestedName { get; set; }
public int NestedIntValue { get; set; }
public decimal NestedDecimalValue { get; set; }
}
public class GameInfo
{
public int UserId { get; set; }
public int MatchesWon { get; set; }
public long BulletsFired { get; set; }
public string LastLevelVisited { get; set; }
public NestedGameInfoObject SuperCoolNestedGameInfo { get; set; }
// thousands more of these
}
Unfortunately, this is coming from an external source... imagine a HUGE data dump from Grand Theft Auto or something.
And I want to get just a small cross section of a list of these objects. Imagine we want to be able to compare you with a bunch of your friends' game info objects. An individual result for one user would look like this:
public class MyResult
{
public int UserId { get; set; } // user id from above object
public string ResultValue { get; set; } // one of the value fields from above with .ToString() executed on it
}
And an example of what I want to replace with something more manageable (believe me, I DON'T want to be maintaining this monster switch statement):
const int MATCHES_WON = 1;
const int BULLETS_FIRED = 2;
const int NESTED_INT = 3;
public static List<MyResult> GetMyResult(GameInfo[] gameInfos, int input)
{
var output = new List<MyResult>();
switch(input)
{
case MATCHES_WON:
output = gameInfos.Select(x => new MyResult()
{
UserId = x.UserId,
ResultValue = x.MatchesWon.ToString()
}).ToList<MyResult>();
break;
case BULLETS_FIRED:
output = gameInfos.Select(x => new MyResult()
{
UserId = x.UserId,
ResultValue = x.BulletsFired.ToString()
}).ToList<MyResult>();
break;
case NESTED_INT:
output = gameInfos.Select(x => new MyResult()
{
UserId = x.UserId,
ResultValue = x.SuperCoolNestedGameInfo.NestedIntValue.ToString()
}).ToList<MyResult>();
break;
// ad nauseum
}
return output;
}
So the question is are there any reasonable ways to manage this beast? What I'd really like is a dynamic way to get this info in case that initial object changes (more game info properties are added, for instance). Is there a better way to architect this so it's less clumsy?
I think your first sentence eluded to what is probably the most reasonable solution: some form of dictionary mapping values to methods.
For example, you could define a static Dictionary<int, func<GameInfo, string>>, where each value such as MATCHES_WON would be added with a corresponding lambda that extracts the appropriate value (assuming your constants, etc are defined as shown in your example):
private static Dictionary<int, Func<GameInfo, string>> valueExtractors =
new Dictionary<int, Func<GameInfo, string>>() {
{MATCHES_WON, gi => gi.MatchesWon.ToString()},
{BULLETS_FIRED, gi => gi.BulletsFired.ToString()},
//.... etc for all value extractions
};
You can then use this dictionary to extract the value in your sample method:
public static List<MyResult> GetMyResult(GameInfo[] gameInfos, int input)
{
return gameInfo.Select(gi => new MyResult()
{
UserId = gi.UserId,
ResultValue = valueExtractors[input](gi)
}).ToList<MyResult>();
}
Outside of this option, you could potentially have some sort of file/database/stored lookup with the number and the property name, then use reflection to extract the value, but that would obviously not perform as well.
I think this code is getting out of hand a bit. You're effectively using constants to index properties - and this is creating fragile code that you're looking to use some technique - such as - reflection, dictionaries, etc - to control the increased complexity.
Effectively the approach that you're using now will end up with code like this:
var results = GetMyResult(gameInfos, BULLETS_FIRED);
The alternative is to define an extension method that lets you do this:
var results = gameInfos.ToMyResults(gi => gi.BulletsFired);
This is strongly-typed, it doesn't require constants, switch statements, reflection, or anything arcane.
Just write these extension methods and you're done:
public static class GameInfoEx
{
public static IEnumerable<MyResult> ToMyResults(
this IEnumerable<GameInfo> gameInfos,
Func<GameInfo, object> selector)
{
return gameInfos.Select(gi => gi.ToMyResult(selector));
}
public static MyResult ToMyResult(
this GameInfo gameInfo,
Func<GameInfo, object> selector)
{
return new MyResult()
{
UserId = gameInfo.UserId,
ResultValue = selector(gameInfo).ToString()
};
}
}
Does that work for you?
You can use reflection for theses purposes. You can implement custom attributes, mark your properties, etc. Also, it is dynamic way to get info about your class if it changes.
If you want to manage switch code I would point you at Design Patterns book (GoF) and suggest possibly looking at patterns like Strategy and possibly Factory (thats when we talk about general case use, your case isn't very suited for Factory) and implementing them.
While switch statement still has to be left somewhere after refactoring to pattern is complete (for example, in a place where you select strategy by id), code will be much more maintanable and clear.
That said about general switch maintenance, if they become beast like, I am not sure its best solution given how similar your case statements look.
I am 100% sure you can create some method (possibly an extension method) that will be accepting desired property accessor lambda, that should be used when results are generated.
If you want your code to be more generic, I agree with the suggestion of a dictionary or some kind of lookup pattern.
You could store functions in the dictionary, but they seemly all perform the same operation - getting the value from a property. This is ripe for reflection.
I'd store all your properties in a dictionary with an enum (prefer an enum to a const) as the key, and a PropertyInfo - or, less preferred, a string which describes the name of the property - as the value. You then call the GetValue() method on the PropertyInfo object to retrieve the value from the object / class.
Here's an example where I'm mapping enum values to their 'same named' properties in a class, and then using reflection to retrieve the values out of a class.
public enum Properties
{
A,
B
}
public class Test
{
public string A { get; set; }
public int B { get; set; }
}
static void Main()
{
var test = new Test() { A = "A value", B = 100 };
var lookup = new Dictionary<Properties, System.Reflection.PropertyInfo>();
var properties = typeof(Test).GetProperties().ToList();
foreach (var property in properties)
{
Properties propertyKey;
if (Enum.TryParse(property.Name, out propertyKey))
{
lookup.Add(propertyKey, property);
}
}
Console.WriteLine("A is " + lookup[Properties.A].GetValue(test, null));
Console.WriteLine("B is " + lookup[Properties.B].GetValue(test, null));
}
You can map your const values to the names of the properties, PropertyInfo objects which relate to those properties, functions which will retrieve the property values... whatever you think suits your needs.
Of course you will need some mapping - somewhere along the way you will be depending on your input value (the const) mapping to a specific property. The method by which you can get this data might determine the best mapping structure and pattern for you.
I think the way to go is indeed some kind of mapping from one value (int) to something that is somehow a function that knows how to extract a value.
If you really want to keep it extensible, so that you can easily add some without touching the code, and possibly accessing more complex properties (ie. nested properties, do some basic computation), you may want to keep that in a separate source.
I think one way to do this is to rely on the Scripting Services, for instance evaluating a simple IronPython expression to extract a value...
For instance in a file you could store something like :
<GameStats>
<GameStat name="MatchesWon" id="1">
<Expression>
currentGameInfo.BulletsFired.ToString()
</Expression>
</GameStat>
<GameStat name="FancyStat" id="2">
<Expression>
currentGameInfo.SuperCoolNestedGameInfo.NestedIntValue.ToString()
</Expression>
</GameStat>
</GameStats>
and then, depending on the requested stat, you always end up retrieving the general GameInfos. You can them have some kind of foreach loop with :
foreach( var gameInfo in gameInfos){
var currentGameInfo = gameInfo
//evaluate the expression for this currentGameInfo
return yield resultOfEvaluation
}
See http://www.voidspace.org.uk/ironpython/dlr_hosting.shtml for examples on how to embed IronPython Scripting in a .NET application.
NOTE: when working with this kind of stuff, there are several things you must really be careful about:
this potentially allows someone to inject code in your application ...
you should measure the performance impact of Dynamic evaluation in here
I don't have a solution to your switch problem off the top of my head, but you could certainly reduce the code by using a class that can automatically map all the fields you need. Check out http://automapper.org/.
I would not have written the GetMyResult method in the first place. All it is doing is transforming GameInfo sequence into MyResult sequence. Doing it with Linq would be easier and more expressive.
Instead of calling
var myResultSequence = GetMyResult(gameInfo, MatchesWon);
I would simply call
var myResultSequence = gameInfo.Select(x => new MyResult() {
UserId = x.UserId,
ResultValue = x.MatchesWon.ToString()
});
To make it more succinct you can pass the UserId and ResultValue in constructor
var myResultSequence =
gameInfo.Select(x => new MyResult(x.UserId, x.MatchesWon.ToString()));
Refactor only if you see the selects getting duplicated too much.
This is one possible way without using reflection:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
public class GameInfo
{
public int UserId { get; set; }
public int MatchesWon { get; set; }
public long BulletsFired { get; set; }
public string LastLevelVisited { get; set; }
// thousands more of these
}
public class MyResult
{
public int UserId { get; set; } // user id from above object
public string ResultValue { get; set; } // one of the value fields from above with .ToString() executed on it
}
public enum DataType
{
MatchesWon = 1,
BulletsFired = 2,
// add more as needed
}
class Program
{
private static Dictionary<DataType, Func<GameInfo, object>> getDataFuncs
= new Dictionary<DataType, Func<GameInfo, object>>
{
{ DataType.MatchesWon, info => info.MatchesWon },
{ DataType.BulletsFired, info => info.BulletsFired },
// add more as needed
};
public static IEnumerable<MyResult> GetMyResult(GameInfo[] gameInfos, DataType input)
{
var getDataFunc = getDataFuncs[input];
return gameInfos.Select(info => new MyResult()
{
UserId = info.UserId,
ResultValue = getDataFunc(info).ToString()
});
}
static void Main(string[] args)
{
var testData = new GameInfo[] {
new GameInfo { UserId="a", BulletsFired = 99, MatchesWon = 2 },
new GameInfo { UserId="b", BulletsFired = 0, MatchesWon = 0 },
};
// you can now easily select whatever data you need, in a type-safe manner
var dataToGet = DataType.MatchesWon;
var results = GetMyResult(testData, dataToGet);
}
}
}
Purely on the question of large switch statements, it is notable that there are 2 variants of the Cyclomatic Complexity metric in common use. The "original" counts each case statement as a branch and so it increments the complexity metric by 1 - which results in a very high value caused by many switches. The "variant" counts the switch statement as a single branch - this is effectively considering it as a sequence of non-branching statements, which is more in keeping with the "understandability" goal of controlling complexity.