This seems to come up alot in my code, i'm wondering if there is some way of removing the switch statement, or if there is a more elegant way of doing it?
public class MetaData
{
public string AlbumArtist { get; set; }
public string AlbumTitle { get; set; }
public string Year { get; set; }
public string SongTitle { get; set; }
public static MetaData CreateMetaDataFrom(IEnumerable<TextFrame> textFrames)
{
var metaData = new MetaData();
foreach (var frame in textFrames)
{
switch (frame.Descriptor.ID)
{
case "TPE1":
metaData.AlbumArtist = frame.Content;
break;
case "TALB":
metaData.AlbumTitle = frame.Content;
break;
case "TIT2":
metaData.SongTitle = frame.Content;
break;
case "TYER":
metaData.Year = frame.Content;
break;
}
}
return metaData;
}
}
This is related to an object-oriented approach. The usual method to get rid of if's or case's is to use a lookup table of criteria and effects. There are other techniques that use this same idea, such as data-directed programming (http://en.wikipedia.org/wiki/Data-directed_programming) and dispatch tables (http://en.wikipedia.org/wiki/Dispatch_table). Many language implementations use type dispatch tables to implement virtual method calls.
The lookup table could be a hashtable populated with lambda functions as so:
Dictionary<string, Func<MetaData, string, string>> lookup = new Dictionary<string, Func<MetaData, string, string>>();
lookup["TPE1"] = (m, v) => m.AlbumArtist = v;
lookup["TALB"] = (m, v) => m.AlbumTitle = v;
lookup["TIT2"] = (m, v) => m.SongTitle = v;
lookup["TYER"] = (m, v) => m.Year = v;
then you assign fields of metaData inside your loop as:
lookup[frame.Descriptor.ID](metaData, frame.Content);
From your code I conclude that IEnumerable<TextFrame> has always 4 members
so you could just write (haven't tried it so check for the syntax):
public static MetaData CreateMetaDataFrom(IEnumerable<TextFrame> textFrames)
{
return new MetaData()
{
metaData.AlbumArtist = textFrames.Where(frame => frame.Descriptor.ID = "TPE1").SingleOrDefault().Content,
metaData.AlbumTitle = textFrames.Where(frame => frame.Descriptor.ID = "TALB").SingleOrDefault().Content,
metaData.SongTitle = textFrames.Where(frame => frame.Descriptor.ID = "TIT2").SingleOrDefault().Content;
metaData.Year = textFrames.Where(frame => frame.Descriptor.ID = "TYER").SingleOrDefault().Content;
};
}
You might want to look at implementing the Strategy Pattern. DimeCasts.Net have an excellent video tutorial that may help.
I was tempted to suggest the Strategy Pattern but you may need a slight variation. Consider writing a method in the TextFrame class, lets call it putContent(MetaData).
Then create subclasses of TextFrame each representing a different Type of Frame. Each subclass will override the putContent(Metadata) method and do its appropraite logic.
PseudoCode Example for TPE1:
Metadata putContent(MetaData md){
md.AlbumArtist = Content;
return md;
}
You MetaData code will then change to:
var metaData = new MetaData();
foreach (var frame in textFrames)
{
metaData = frame.putContent(metaData);
}
return metaData;
Of course, to create the TextFrames them selves will then require a Factory so this is not the end of the story.
It seems like you know what the types will be before hand (using a switch) so why not just retrieve the values as required, without a for switch.
Examples are when using a hashtable, and you know what fields will be available, just use the fields.
ig you are not sure if the field is available, a simple test will be sufficiant if the list contains the value.
You can then even write a helper function to check and return the value if the list has the value.
What you really have here is a four-way setter. The canonical refactoring here is "Replace Parameter with Explicit Methods" (p285 of Refactoring by Martin Fowler). The Java example he gives is changing:
void setValue(String name, int value) {
if (name.equals("height")) {
_height = value;
return;
}
if (name.equals("width")) {
_width = value;
return;
}
}
to:
void setHeight(int arg) {
_height = arg;
}
void setWidth(int arg) {
_width = arg;
}
Assuming that the caller of CreateMetaDataFrom() knows what it's passing in, you could skip the switch/case and use the actual setters for those properties.
Related
I have to following C#-code quite a lot:
public void UpdateDB(Model.ResultContext db)
{
Model.Planning.Part dbPart = db.Parts.Where(/*someClause*/).FirstOrDefault();
//The awkward part
if (dbPart.Number != Number)
{
dbPart.Number = Number;
}
if (dbPart.NumberShort != NumberShort)
{
dbPart.NumberShort = NumberShort;
}
if (dbPart.Designation != Designation)
{
dbPart.Designation = Designation;
}
}
It is obviously kind of awkward to check every field and wrap it in if != then set
Yes, the check is needed because otherwise the database sees everything as changed columns.
The fields to set are auto-Properties:
public class Part
{
[MaxLength(36), MinLength(1)]
public string Number { get; set; } = null!;
[MaxLength(80)]
public string Designation { get; set; } = null!;
}
and I don't want to write an explicit setter for every field which of course could do the checking before setting.
So what I thought of is some Method ´SetIfChanged´ which is called like this to make the code more readable and less error-prone:
//Options
dbPart.SetIfChanged(dbPart.Number, this.Number);
dbPart.SetIfChanged(dbPart.Number = this.Number);
dbPart.SetIfChanged(Number, this.Number);
I think something like that is possible with expressions or lambdas but to be honest... I'm stuck with the syntax of declaring and calling such a method
Anybody can help me out?
Unfortunately, C# is lacking a number of things to help you with this (e.g. property refs or extension methods on reference objects), but you can use Reflection to help with this. It is likely to be quite slow, however.
With a method that takes a lambda, you can write a set method:
public static void SetIfDifferent<T>(Expression<Func<T>> getterFnE, T newVal) {
var me = (MemberExpression)getterFnE.Body;
var target = me.Expression;
var targetLambda = Expression.Lambda(target);
var prop = me.Member;
var oldVal = getterFnE.Compile().Invoke();
if ((oldVal == null && newVal != null) || !oldVal.Equals(newVal)) {
var obj = targetLambda.Compile().DynamicInvoke();
prop.SetValue(obj, newVal);
}
}
This would be used like:
SetIfDifferent(() => dbPart.Number, Number);
SetIfDifferent(() => dbPart.NumberShort, NumberShort);
SetIfDifferent(() => dbPart.Designation, Designation);
This would be slow because of the need to compile the Expression trees and use DynamicInvoke. One way to speed it up would be to pass in a setter and getter lambda instead, but that leads to as much duplication as your original code.
If you would be willing to pass the object and name of the property instead, you could use:
public static T GetValue<T>(this MemberInfo member, object srcObject) => (T)member.GetValue(srcObject);
public static void SetIfDifferent2<TObj, TField>(this TObj obj, string fieldName, TField newVal) {
var prop = typeof(TObj).GetProperty(fieldName);
var oldVal = prop.GetValue<TField>(fieldName);
if ((oldVal == null && newVal != null) || !oldVal.Equals(newVal))
prop.SetValue(obj, newVal);
}
Which you could use like:
dbPart.SetIfDifferent2(nameof(dbPart.Number), Number);
dbPart.SetIfDifferent2(nameof(dbPart.NumberShort), NumberShort);
dbPart.SetIfDifferent2(nameof(dbPart.Designation), Designation);
Unfortunately, it requires repeating dbPart unless you are willing to just put in the field name (e.g. "Number") but that will cause runtime errors if the field changes.
You could also cache the PropertyInfo instead of looking it up with GetProperty, but that is generally pretty fast and caching probably isn't worth it.
Well if you really need checking (lets say at the end you want to know if anything has been changed or not) you can use Reflection and loop through properties. but in your case no check is needed.
take this for instance:
if (dbPart.Number != Number)
{
dbPart.Number = Number;
}
true) if the value is different you are setting the new one
false) means that the new value and the old value are the same, so doesn't hurt to set it again
If you want to know if anything has changed at the end:
bool changed = false;
var type = dbPart.GetType();
foreach(var (PropertyInfo)pi in type.GetProperties()
{
if(pi.GetValue(dbPart) != newValue)
{
changed = true;
pi.SetValue(dbPart, newValue);
}
}
or you can do something like:
bool changed = dbPart.Number != Number || dbPart.Designation != Designation;
dbPart.Number = Number;
dbPart.Designation = Designation;
I've searched in vain mainly because I don't think I know what to look for. I think I need to use the Find method for Lists in C# to do what I want, but I can't seem to get it right. This leads me to think one of two obvious scenarios is happening:
1) I'm going about this the wrong way (my money is on this one).
2) I'm going about this the right way, but I just don't understand the syntax for finding something.
Also, just to answer some of the "Why are you..." or "Why haven't you..." questions: If you can't tell, I'm figuring this out as I go along - and this is about the extent of what I've been able to teach myself thus far.
Here is what I'm trying to do:
First, I have a list<FitHeaderCard> object called HeaderBlock. and it is populated by this custom type:
public class FitHeaderCard
{
public string keyword;
public string value;
public string comment;
//Constructor
public FitHeaderCard()
{}
public FitHeaderCard(string fitHeaderCard)
{ // input: 80 byte string containing 3 fixed width delimited values.
keyword = fitHeaderCard.Substring(0, 8).Trim();
value = fitHeaderCard.Substring(10, 20).Trim();
comment = fitHeaderCard.(33,47).Trim();
}
public FitHeaderCard(FitHeaderCard fitHeaderCard)
{ //clone a FitHeaderCard
keyword = fitHeaderCard.keyword;
value = fitHeaderCard.value;
comment = fitHeaderCard.comment;
}
}
The header cards are fed into a list when read from a file on my hard drive (using a BinaryReader).
The FitHeader object code is as follows:
public class FitHeader
{
public string headerCard;
public string headerSize;
public FitHeaderCard fitHeaderCard = new FitHeaderCard();
public List<FitHeaderCard> HeaderBlock = new List<FitHeaderCard>();
//Constructor
public FitHeader()
{
}
public FitHeader(string _headerCard)
{
headerCard = _headerCard;
}
public FitHeaderCard FitHeaderCard
{
get;
private set;
}
//Methods
public void AddHeaderCard(string _headerCard)
{
FitHeaderCard = new FitHeaderCard(_headerCard);
HeaderBlock.Add(FitHeaderCard);
}
public List<FitHeaderCard> GetHeader()
{
return HeaderBlock;
}
public int GetHeaderSize();
{
return headerSize = //some convoluted math but it works!
}
//This is what I'm having trouble with
public FitHeaderCard GetFitHeaderCard(string _keyword)
{
HeaderBlock.Find("BITPIX");
fitHeaderCard = new FitHeaderCard(fitHeaderCard); // clone constructor
return fitHeaderCard;
}
}
So the GetFitHeaderCard method is supposed to take in a keyword, and return the the entire FitHeaderCard object found in the HeaderBlock list.
Optionally, I'd love to just get the Value back, possibly in a separate method, but for now, I can live with just referencing the value of FitHeaderCard.Value
Thanks in advance for your help! I look forward to face palming myself when an elegant and obvious answer is revealed to this newbie .Net coder!
The Find method of List requires a predicate(i.e. a function that takes in an element, does some calculation on it, and returns a boolean). Right now you're passing a string. That's not a predicate. What you might do instead is create either a separate method, anonymous function, or lambda that matches what I just specified:
(separate method; could also be local function)
...
//This is what I'm having trouble with
public FitHeaderCard GetFitHeaderCard(string _keyword)
{
fitHeaderCard = HeaderBlock.Find(FilterByBitPix);
fitHeaderCard = new FitHeaderCard(fitHeaderCard); // clone constructor
return fitHeaderCard;
}
public FitHeaderCard FilterByBitPix(FitHeaderCard item)
{
return item.keyword == "BITPIX";
}
}
OR (anonymous function)
...
//This is what I'm having trouble with
public FitHeaderCard GetFitHeaderCard(string _keyword)
{
fitHeaderCard = HeaderBlock.Find(delegate (FitHeaderCard item) { return item.keyword == "BITPIX"); };
fitHeaderCard = new FitHeaderCard(fitHeaderCard); // clone constructor
return fitHeaderCard;
}
}
OR (lambda)
...
//This is what I'm having trouble with
public FitHeaderCard GetFitHeaderCard(string _keyword)
{
fitHeaderCard = HeaderBlock.Find(item => item.keyword == "BITPIX");
fitHeaderCard = new FitHeaderCard(fitHeaderCard); // clone constructor
return fitHeaderCard;
}
}
List<FitHeaderCard> matches = HeaderBlock.Where(p=>p.SomePublicStringPropertyInYourObject.Contains(searchString));
You want to code with C#, my advice: learn linq queries ASAP. It is very powerful for extracting what you need from lists.
Given that you have a List<>, there are a number of LINQ-based queries you can use to extract this information. In your particular example, this is probably the simplest:
var returnValue = HeaderBlock.FirstOrDefault(hb => hb.keyword.Equals("BITPIX"))?.value;
As the name suggests FirstOrDefault, this will return either the first item it finds in the list that matches, or the default value (which in this case is NULL because it is a list of objects).
There are other LINQ extensions you could use, such as:
First, which throws an exception if it can't find the keword;
var first = HeaderBlock.FirstOrDefault(hb => hb.keyword.Equals("BITPIX")).value;
Where, which returns a collection;
var foundItems = HeaderBlock.Where(hb => hb.keyword.Equals("BITPIX"));
Single, which is similar to First, but will throw an exception if there is more than one;
var single = HeaderBlock.Single(hb => hb.keyword.Equals("BITPIX")).value;
and SingleOrDefault, which again is similar to Single but will return NULL if it can't find anything.
var singleOrDefault = HeaderBlock.SingleOrDefault(hb => hb.keyword.Equals("BITPIX"))?.value;
LINQ is really important and incredibly powerful, and there is a lot of literature available to help you (admittedly, I personally found the official documentation quite hard to read, and hard to grasp the actual syntax in usage).
I have been working on a small mathematical scripting engine (or DSL, if you prefer). Making it for fun, its nothing serious. In any case, one of the features I want is the ability to get results from it in a type safe manner. The problem is that there are 5 different types that it can return.
Number, bool, Fun, FunN and NamedValue. There is also AnyFun which is a abstract base class for Fun and FunN. The difference between Fun and FunN is that Fun only takes one argument, while FunN takes more then one argument. Figured it was common enough with one argument to warrant a separate type (could be wrong).
At the moment, I am using a wrapper type called Result and a class called Matcher to accomplish this (inspired by pattern matching in languages like F# and Haskell). It basically looks like this when you use it.
engine.Eval(src).Match()
.Case((Number result) => Console.WriteLine("I am a number"))
.Case((bool result) => Console.WriteLine("I am a bool"))
.Case((Fun result) => Console.WriteLine("I am a function with one argument"))
.Case((AnyFun result) => Console.WriteLine("I am any function thats not Fun"))
.Do();
This is my current implementation. It is rigid, though. Adding new types is rather tedious.
public class Result
{
public object Val { get; private set; }
private Callback<Matcher> _finishMatch { get; private set; }
public Result(Number val)
{
Val = val;
_finishMatch = (m) => m.OnNum(val);
}
public Result(bool val)
{
Val = val;
_finishMatch = (m) => m.OnBool(val);
}
... more constructors for the other result types ...
public Matcher Match()
{
return new Matcher(this);
}
// Used to match a result
public class Matcher
{
internal Callback<Number> OnNum { get; private set; }
internal Callback<bool> OnBool { get; private set; }
internal Callback<NamedValue> OnNamed { get; private set; }
internal Callback<AnyFun> OnAnyFun { get; private set; }
internal Callback<Fun> OnFun { get; private set; }
internal Callback<FunN> OnFunN { get; private set; }
internal Callback<object> OnElse { get; private set; }
private Result _result;
public Matcher(Result r)
{
OnElse = (ignored) =>
{
throw new Exception("Must add a new exception for this... but there was no case for this :P");
};
OnNum = (val) => OnElse(val);
OnBool = (val) => OnElse(val);
OnNamed = (val) => OnElse(val);
OnAnyFun = (val) => OnElse(val);
OnFun = (val) => OnAnyFun(val);
OnFunN = (val) => OnAnyFun(val);
_result = r;
}
public Matcher Case(Callback<Number> fn)
{
OnNum = fn;
return this;
}
public Matcher Case(Callback<bool> fn)
{
OnBool = fn;
return this;
}
... Case methods for the rest of the return types ...
public void Do()
{
_result._finishMatch(this);
}
}
}
The thing is that I want to add more types. I want to make so functions can return both numbers and bools, and change Fun to Fun< T >, where T is the return type. This is actually where the main problem lies. I have AnyFun, Fun, FunN, and after introducing this change I would have to deal with AnyFun, Fun< Number >, Fun< bool >, FunN< Number >, FunN< bool >. And even then I would want it to match AnyFun against any function that isnt matched themselves. Like this:
engine.Eval(src).Match()
.Case((Fun<Number> result) => Console.WriteLine("I am special!!!"))
.Case((AnyFun result) => Console.WriteLine("I am a generic function"))
.Do();
Does anyone have any suggestions for a better implementation, that handles adding new types better? Or are there any other suggestions for how to get the result in a type safe manner? Also, should I have a common base class for all the return types (and add a new type for bool)?
Performance is not an issue, btw.
Take care,
Kerr
EDIT:
After reading the feedback, I have created this matcher class instead.
public class Matcher
{
private Action _onCase;
private Result _result;
public Matcher(Result r)
{
_onCase = null;
_result = r;
}
public Matcher Case<T>(Callback<T> fn)
{
if (_result.Val is T && _onCase == null)
{
_onCase = () => fn((T)_result.Val);
}
return this;
}
public void Else(Callback<object> fn)
{
if (_onCase != null)
_onCase();
else
fn(_result.Val);
}
public void Do()
{
if (_onCase == null)
throw new Exception("Must add a new exception for this... but there was no case for this :P");
_onCase();
}
}
Its shorter, but the order of the cases matter. For example, in this case the Fun option will never run.
.Case((AnyFun result) => Console.WriteLine("AAANNNNNNNYYYYYYYYYYYYY!!!!"))
.Case((Fun result) => Console.WriteLine("I am alone"))
But it will if you switch places.
.Case((Fun result) => Console.WriteLine("I am alone"))
.Case((AnyFun result) => Console.WriteLine("AAANNNNNNNYYYYYYYYYYYYY!!!!"))
Is it possible to improve that? Are there any other issues with my code?
EDIT 2:
Solved it :D.
Your matcher could handle unlimited types by doing something like this:
public class Matcher
{
private readonly Result result; // pass this in
private readonly List<Func<Result, bool>> cases = new ...();
public Matcher Case<T>(Action<T> action)
{
cases.add(result =>
{
if(typeof(T).IsAssignableFrom(result.Value.GetType()))
{
action((T)(result.Value));
return true;
}
return false;
}
return this;
}
public void Do()
{
for each(var #case in cases)
{
if(#case(result)) return;
}
}
}
I think you don't actually need a list, unless your Result doesn't have a Value until later on. I don't quite understand your object model, but if the type of the result is known, then don't use a list and just do the type test immediately.
If you always want to treat a DSL result in the same way
If you always want to treat a result in the same way (such as if you always want to convert/adapt a specific type of DSL object in the same manner), I suggest using one or more dictionaries where you put adapter delegates like this.
I don't know exactly how you plan to extend your application, but it seems to me like it's a good idea in your case to have one separate dictionary per return type, and let them all have zero or one input parameters. (Instead of using several parameters, just wrap the DSL parameters that you want to return into one single object).
An example:
public class SomeClass
{
public IDictionary<Type, Action<object>> RegistryVoid { get; set; }
public IDictionary<Type, Func<object, int>> RegistryInt { get; set; }
public void SomeDlsMethod()
{
...
// Example when you need to convert your DSL data object to int:
int value = RegistryInt[someDslObject.GetType()](someDslObject);
}
}
If you want to treat a DSL result differently
If you want to treat a DSL result differently in your code, I suggest using the TypeSwith found here. TypeSwitch is simply a simpler way than using multiple if/else-statements and casting. With this approach you can specify the logic where you use it, so you are not limited to the logic you put into the dictionaries. (TypeSwitch can easily be modified to become an extension method if you prefer that).
Example:
public class SomeClass
{
public void SomeDlsMethod()
{
TypeSwitch.Do(someDslObject,
TypeSwitch.Case<DslObjectA>(someDslObjectA => ...),
TypeSwitch.Case<DslObjectB>(someDslObjectB => ...),
TypeSwitch.Default(() => ...)
);
}
}
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.