Multiple condition for one if value - c#

public enum Waypointtype { Start, Point, End };
Waypoint currentPoint = m_ListPoints[i];
if(currentPoint.Type == (Waypointtype.Start || Waypointtype.End))
Hello, is there a way do this "if" like above in c#? I am bit lazy and always searching to find a way to write shorter code. Or is the only way like below?
if (currentPoint.Type == Waypointtype.Start || currentPoint.Type == Waypointtype.End)

I don't think there's a shorter way than what you already have. There are two other approaches that I can think of. For example, you could use a switch statement:
switch (currentPoint.Type)
{
case Waypointtype.Start:
case Waypointtype.End:
// do stuff
break;
default:
// default case
break;
}
Or you could use an array with contains:
if (new [] { Waypointtype.Start, Waypointtype.End }.Contains(currentPoint.Type))
In my opinion, the switch conveys intent better here.

Flag attribute can be right tool for the job
[Flags]
public enum Waypointtype
{
Start = 1,
Point = 2,
End = 4
};
Notice that enumeration values should be in powers of two: 1, 2, 4, 8, and so on.
Usage
const Waypointtype StartOrEnd = Waypointtype.Start | Waypointtype.End;
var current = Waypointtype.Start;
if ((StartOrEnd & current) == current)
{
// current type is one of values from test type.
}

Right answer should be #Fabio's answer of using enum Flag attribute.
But, because we are using object-oriented programming language, we should benefit from it.
Condition uses class Waypoint and it's property Type of enum type Waypointtype.
So only class should know "am I of start or end type?".
By encapsulating condition within class we can provide readable name and protect class consumers from knowing implementation details.
// Use FlagAttribut
[Flag]
public enum WaypointType { Start = 1, Point = 2, End = 4 };
public class Waypoint
{
private const WaypointType START_OR_END = WaypointType.Start | WaypointType.End;
public WaypointType Type { get; set; }
public bool IsStartOrEnd => (StartOrEnd & Type) == Type;
}
Usage become short, readable and reusable.
Waypoint currentPoint = m_ListPoints[i];
if (currentPoint.IsStartOrEnd())
{
// do staff
}
Notice that we(developers) are reading code much more than writing it (80% vs 20% maybe).
So instead of writing short code, write it in the way it can be read and understood quickly.
Sometimes it can be dome by writing short code and sometimes it can be done by encapsulating short code under comprehensible structure.

You could add an extension method for Waypoint:
public static class WaypointExtensions
{
public static bool IsStartOrEnd(this Waypoint waypoint)
{
if (waypoint == null)
{
return false;
}
return (waypoint.Type == Waypointtype.Start || waypoint.Type == Waypointtype.End);
}
}
And then use it like:
Waypoint currentPoint = m_ListPoints[i];
if(currentPoint.IsStartOrEnd())
{
...
}

Related

C# reflections with enum as string

I have a structure that contains an enum:
public enum MyEnum
{
happy = 0,
sad
}
public struct MyStruct
{
public MyEnum feelings;
public int boopCounter;
}
and then I am given a text/string version of a structure and its contents:
feelings = sad
boopCounter = 12
I am trying to write a generic parser that can generate a struct object with the correctly populated fields, without having to modify the parser every time the structure gets updated. I have been generally successful using Reflections:
// Scan through each member of the structure, looking for a match
foreach (var field in typeof(MyStruct).GetFields(System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Public))
{
if(field.Name == fieldNameFromText)
{
// This is the member we need to update. Treat enums differently
var fld = typeof(MyStruct).GetField(field.Name);
if(field.FieldType.IsEnum)
{
//fld.SetValue(s, Enum.ToObject(field.FieldType, valFromText)); // Didn't work
fld.SetValue(s, Convert.ChangeType(Enum.ToObject(field.FieldType, Convert.ToInt32(valFromText)), field.FieldType)); // Worked, but only if integer version of enum is passed in
}
else
{
// Not an enum, parse directly.
fld.SetValue(s, Convert.ChangeType(valFromText, field.FieldType));
}
break;
}
}
So this code works, but it only works if my input text contains the integer version of the enum:
feelings = 1
boopCounter = 12
Is there a way to get this to work with the original string enumeration input ("sad") ? I'd like to keep it generic if possible (notice how my code doesn't ever specifically call out "MyEnum" anywhere).
Yes, you can use the non-generic version of Enum.Parse.
var fieldType = fld.FieldType;
if (fieldType.IsEnum)
{
var valueToAssign = Enum.Parse(fieldType, valFromText);
fld.SetValue(s, valueToAssign);
}

Is there a cleaner way to represent this idiom in C#? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I am using a struct in a project, like so:
struct Position
{
public int X { get; private set; }
public int Y { get; private set; }
// etc
}
I would like to add a method that allows me to create a modified copy of the struct with arbitrarily changed properties. For example, it would be convenient to use this:
var position = new Position(5, 7);
var newPos = position.With(X: position.X + 1);
Is this idiom hacky? Are there better ways to support this?
public Position With(int? X = null, int? Y = null)
{
return new Position(X ?? this.X, Y ?? this.Y);
}
Edit: in case it was unclear, the struct is immutable, I simply want to create a new value with some values modified. Incidentally, this is very similar to Haskell's syntactic sugar for records, where one would write newPos = oldPos { x = x oldPos + 1 }. This is just a bit experimental as to whether such an idiom is helpful in C#.
Personally, I consider the idiom of a plain-old-data-struct to be vastly underrated. Mutable structs which encapsulate state in anything other than public fields are problematic, but sometimes it's useful to bind together a fixed collection of variables stuck together with duct tape so they can be passed around as a unit. A plain-old-data-struct is a perfect fit for that usage; it behaves like a fixed collection of variables stuck together with duct tape, since that's what it is. One can with some work come up with an immutable class which requires slow and hard-to-read code to do anything with, or with some more work come up with something that's still slow but not quite so unaesthetic; one can also code structures in such fashion as to mimic such classes. In many cases, however, the only effect of going through all that effort is that one's code will be slower and less clear than it would have been if one had simply used a PODS.
The key thing that needs to be understood is that a PODS like struct PersonInfo { public string Name, SSN; public Date Birthdate; } does not represent a person. It represents a space that can hold two strings and a date. If one says var fredSmithInfo = myDatabase.GetPersonInfo("Fred Smith");, then FredSmithInfo.BirthDate doesn't represent Fred Smith's birthdate; it represents a variable of type Date which is initially loaded with the value returned by a call to GetPersonInfo--but like any other variable of type Date, could be changed to hold any other date.
That's about as neat a way as you're going to get. Doesn't seem particularly hacky to me.
Although in cases where you're just doing position.X + 1 it'd be neater to have something that was like:
var position = new Position(5,7);
var newPos = position.Add(new Position(1,0));
Which would give you a modified X value but not a modified Y value.
One could consider this approach as a variant of the prototype pattern where the focus is on having a template struct rather than avoiding the cost of new instances. Whether the design is good or bad depends on your context. If you can make the message behind the syntax clear (I think the name With you're using is a bit unspecific; maybe something like CreateVariant or CreateMutant would make the intention clearer), I would consider it an appropriate approach.
I'm adding an expression based form as well. Do note the horrendous boxing/unboxing which needs to be done due to the fact that it is a struct.
But as one can see the format is quite nice:
var p2 = p.With(t => t.X, 4);
var p3 = p.With(t => t.Y, 7).With(t => t.X, 5); // Yeah, replace all the values :)
And the method is really applicable to all kinds of types.
public void Test()
{
var p = new Position(8, 3);
var p2 = p.With(t => t.X, 4);
var p3 = p.With(t => t.Y, 7).With(t => t.X, 5);
Console.WriteLine(p);
Console.WriteLine(p2);
Console.WriteLine(p3);
}
public struct Position
{
public Position(int X, int Y)
{
this._X = X; this._Y = Y;
}
private int _X; private int _Y;
public int X { get { return _X; } private set { _X = value; } }
public int Y { get { return _Y; } private set { _Y = value; } }
public Position With<T, P>(Expression<Func<Position, P>> propertyExpression, T value)
{
// Copy this
var copy = (Position)this.MemberwiseClone();
// Get the expression, might be both MemberExpression and UnaryExpression
var memExpr = propertyExpression.Body as MemberExpression ?? ((UnaryExpression)propertyExpression.Body).Operand as MemberExpression;
if (memExpr == null)
throw new Exception("Empty expression!");
// Get the propertyinfo, we need this one to set the value
var propInfo = memExpr.Member as PropertyInfo;
if (propInfo == null)
throw new Exception("Not a valid expression!");
// Set the value via boxing and unboxing (mutable structs are evil :) )
object copyObj = copy;
propInfo.SetValue(copyObj, value); // Since struct are passed by value we must box it
copy = (Position)copyObj;
// Return the copy
return copy;
}
public override string ToString()
{
return string.Format("X:{0,4} Y:{1,4}", this.X, this.Y);
}
}

List all bit names from a flag Enum

I'm trying to make a helper method for listing the names of all bits set in an Enum value (for logging purposes). I want have a method that would return the list of all the Enum values set in some variables. In my example
[Flag]
Enum HWResponse
{
None = 0x0,
Ready = 0x1,
Working = 0x2,
Error = 0x80,
}
I feed it 0x81, and it should provide me with a IEnumerable<HWResponse> containing {Ready, Error}.
As I didn't find a simpler way, I tried to write the code below, but I can't make it compile.
public static IEnumerable<T> MaskToList<T>(Enum mask)
{
if (typeof(T).IsSubclassOf(typeof(Enum)) == false)
throw new ArgumentException();
List<T> toreturn = new List<T>(100);
foreach(T curValueBit in Enum.GetValues(typeof (T)).Cast<T>())
{
Enum bit = ((Enum) curValueBit); // Here is the error
if (mask.HasFlag(bit))
toreturn.Add(curValueBit);
}
return toreturn;
}
On this version of the code, the compiler complains that it can't cast T to Enum.
What did I do wrong? Is there a better (simpler) way to do this? How could I make the cast?
Also, I tried to write the method as
public static IEnumerable<T> MaskToList<T>(Enum mask) where T:Enum
but Enum is of a special type that forbids the 'where' syntax (Using C# 4.0)
Here's a simple way to write it using LINQ:
public static IEnumerable<T> MaskToList<T>(Enum mask)
{
if (typeof(T).IsSubclassOf(typeof(Enum)) == false)
throw new ArgumentException();
return Enum.GetValues(typeof(T))
.Cast<Enum>()
.Where(m => mask.HasFlag(m))
.Cast<T>();
}
If your desired end result is a string list of names, just call mask.ToString().
What would you do if the enum were defined like this:
[Flags]
enum State
{
Ready = 1,
Waiting = 2,
ReadyAndWaiting = 3
}
As to resolving the compiler error, this should do it:
Enum bit = (Enum)(object)curValueBit;
Jon Skeet has a project called unconstrained melody that allows you to add the enum constraint, after compilation, by rewriting the IL. This works because the CLR supports such a constraint, even though C# does not.
Another thought: It will be more efficient to cast the return value of GetValues directly to T[]:
foreach(T curValueBit in (T[])Enum.GetValues(typeof (T)))
Building on Gabe's answer I came up with this :
public static class EnumHelper<T>
where T : struct
{
// ReSharper disable StaticFieldInGenericType
private static readonly Enum[] Values;
// ReSharper restore StaticFieldInGenericType
private static readonly T DefaultValue;
static EnumHelper()
{
var type = typeof(T);
if (type.IsSubclassOf(typeof(Enum)) == false)
{
throw new ArgumentException();
}
Values = Enum.GetValues(type).Cast<Enum>().ToArray();
DefaultValue = default(T);
}
public static T[] MaskToList(Enum mask, bool ignoreDefault = true)
{
var q = Values.Where(mask.HasFlag);
if (ignoreDefault)
{
q = q.Where(v => !v.Equals(DefaultValue));
}
return q.Cast<T>().ToArray();
}
}
I organized things a bit differently, namely I put the type check (i.e.: the verification that T is really an enumeration) and the obtaining of the enum values in the static constructor so this is done only once (this would be a performance improvement).
Another thing, I added an optional parameter so you can ignore the typical "zero" / "None" / "NotApplicable" / "Undefined" / etc value of the enumeration.
I spent some time on searching how to convert Flags enum value to List.
I have found pretty simple solution, maybe it will help someone.
[Flags]
public enum Tag
{
None = 0,
Stablecoin = 1,
NativeTokens = 2,
Dex = 4
}
var values = Tag.Stablecoin | Tag.Dex;
var str = values.ToString(); //"Stablecoin, Dex"
var list = uniqueNftTagsV2.Split(", "); //{"Stablecoin","Dex"}
What if just do something like this:
public static IEnumerable<T> MaskToList<T>(Enum mask)
{
if (typeof(T).IsSubclassOf(typeof(Enum)) == false)
throw new ArgumentException();
List<T> toreturn = new List<T>(100);
foreach(T curValueBit in Enum.GetValues(typeof (T)).Cast<T>())
{
Enum bit = (curValueBit as Enum); // The only difference is actually here,
// use "as", instead of (Enum) cast
if (mask.HasFlag(bit))
toreturn.Add(curValueBit);
}
return toreturn;
}
As the as has not compile time check. Compiler here just "believes" you, hoping that you know what you're doing, so the compile time error not raised.

How to implement VARIANT in Protobuf

As part of my protobuf protocol I require the ability to send data of a dynamic type, a little bit like VARIANT. Roughly I require the data to be an integer, string, boolean or "other" where "other" (e.g. DateTime) is serialized as a string. I need to be able to use these as a single field and in lists in a number of different locations in the protocol.
How can this best be implemented while keeping message size minimal and performance optimal?
I'm using protobuf-net with C#.
EDIT:
I've posted a proposed answer below which uses what I think is the minimum of memory required.
EDIT2:
Created a github.com project at http://github.com/pvginkel/ProtoVariant with a complete implementation.
Jon's multiple optionals covers the simplest setup, especially if you need cross-platform support. On the .NET side (to ensure you don't serialize unnecessary values), simply return null from any property that isn't a match, for example:
public object Value { get;set;}
[ProtoMember(1)]
public int? ValueInt32 {
get { return (Value is int) ? (int)Value : (int?)null; }
set { Value = value; }
}
[ProtoMember(2)]
public string ValueString {
get { return (Value is string) ? (string)Value : null; }
set { Value = value; }
}
// etc
You can also do the same using the bool ShouldSerialize*() pattern if you don't like the nulls.
Wrap that up in a class and you should be fine to use that at either the field level or list level. You mention optimal performance; the only additional thing I can suggest there is to perhaps consider treating as a "group" rather than "submessage", as this is easier to encode (and just as easy to decode, as long as you expect the data). To do that, use the Grouped data-format, via [ProtoMember], i.e.
[ProtoMember(12, DataFormat = DataFormat.Group)]
public MyVariant Foo {get;set;}
However, the difference here can be minimal - but it avoids some back-tracking in the output stream to fix the lengths. Either way, in terms of overheads a "submessage" will take at least 2 bytes; "at least one" for the field-header (perhaps taking more if the 12 is actually 1234567) - and "at least one" for the length, which gets bigger for longer messages. A group takes 2 x the field-header, so if you use low field-numbers this will be 2 bytes regardless of the length of the encapsulated data (it could be 5MB of binary).
A separate trick, useful for more complex scenarios but not as interoperable, is generic inheritance, i.e. an abstract base class that has ConcreteType<int>, ConcreteType<string> etc listed as subtypes - this, however, takes an extra 2 bytes (typically), so is not as frugal.
Taking another step further away from the core spec, if you genuinely can't tell what types you need to support, and don't need interoperability - there is some support for including (optimized) type information in the data; see the DynamicType option on ProtoMember - this takes more space than the other two options.
You could have a message like this:
message Variant {
optional string string_value = 1;
optional int32 int32_value = 2;
optional int64 int64_value = 3;
optional string other_value = 4;
// etc
}
Then write a helper class - and possibly extension methods - to ensure that you only ever set one field in the variant.
You could optionally include a separate enum value to specify which field is set (to make it more like a tagged union) but the ability to check the optional fields just means the data is already there. It depends on whether you want the speed of finding the right field (in which case add the discriminator) or the space efficiency of only including the data itself (in which case don't add the discriminator).
That's a general Protocol Buffer approach. There may be something more protobuf-net specific, of course.
Asking questions always helps me think. I found a way to get the number of bytes used for transfer to a bare minimum.
What I've done here is make use of optional properties. Say I want to send an int32. When the value isn't zero, I can just check a property on the message for whether it has a value. Otherwise, I set a type to INT32_ZERO. This way I can correctly store and reconstruct the value. The example below has this implementation for a number of types.
The .proto file:
message Variant {
optional VariantType type = 1 [default = AUTO];
optional int32 value_int32 = 2;
optional int64 value_int64 = 3;
optional float value_float = 4;
optional double value_double = 5;
optional string value_string = 6;
optional bytes value_bytes = 7;
optional string value_decimal = 8;
optional string value_datetime = 9;
}
enum VariantType {
AUTO = 0;
BOOL_FALSE = 1;
BOOL_TRUE = 2;
INT32_ZERO = 3;
INT64_ZERO = 4;
FLOAT_ZERO = 5;
DOUBLE_ZERO = 6;
NULL = 7;
}
And accompanying partial .cs file:
using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
namespace ConsoleApplication6
{
partial class Variant
{
public static Variant Create(object value)
{
var result = new Variant();
if (value == null)
result.Type = VariantType.NULL;
else if (value is string)
result.ValueString = (string)value;
else if (value is byte[])
result.ValueBytes = (byte[])value;
else if (value is bool)
result.Type = (bool)value ? VariantType.BOOLTRUE : VariantType.BOOLFALSE;
else if (value is float)
{
if ((float)value == 0f)
result.Type = VariantType.FLOATZERO;
else
result.ValueFloat = (float)value;
}
else if (value is double)
{
if ((double)value == 0d)
result.Type = VariantType.DOUBLEZERO;
else
result.ValueDouble = (double)value;
}
else if (value is decimal)
result.ValueDecimal = ((decimal)value).ToString("r", CultureInfo.InvariantCulture);
else if (value is DateTime)
result.ValueDatetime = ((DateTime)value).ToString("o", CultureInfo.InvariantCulture);
else
throw new ArgumentException(String.Format("Cannot store data type {0} in Variant", value.GetType().FullName), "value");
return result;
}
public object Value
{
get
{
switch (Type)
{
case VariantType.BOOLFALSE:
return false;
case VariantType.BOOLTRUE:
return true;
case VariantType.NULL:
return null;
case VariantType.DOUBLEZERO:
return 0d;
case VariantType.FLOATZERO:
return 0f;
case VariantType.INT32ZERO:
return 0;
case VariantType.INT64ZERO:
return (long)0;
default:
if (ValueInt32 != 0)
return ValueInt32;
if (ValueInt64 != 0)
return ValueInt64;
if (ValueFloat != 0f)
return ValueFloat;
if (ValueDouble != 0d)
return ValueDouble;
if (ValueString != null)
return ValueString;
if (ValueBytes != null)
return ValueBytes;
if (ValueDecimal != null)
return Decimal.Parse(ValueDecimal, CultureInfo.InvariantCulture);
if (ValueDatetime != null)
return DateTime.Parse(ValueDatetime, CultureInfo.InvariantCulture);
return null;
}
}
}
}
}
EDIT:
Further comments from #Marc Gravell have improved the implementation significantly. See the Git repository for a complete implementation of this concept.
Actually protobuf doesn't support any kind of VARIANT types.
You can try to play around using Unions, see more details here
The main idea is to define message wrapper with all existing message types as optional field, and by using union just specify which type of this concrete message it is.
See example by following the link above.
I use ProtoInclude with an abstract base type and subclasses to get the type and single value statically set. Here's the start of what that could look like for Variant:
[ProtoContract]
[ProtoInclude(1, typeof(Integer))]
[ProtoInclude(2, typeof(String))]
public abstract class Variant
{
[ProtoContract]
public sealed class Integer
{
[ProtoMember(1)]
public int Value;
}
[ProtoContract]
public sealed class String
{
[ProtoMember(1)]
public string Value;
}
}
Usage:
var foo = new Variant.String { Value = "Bar" };
var baz = new Variant.Integer { Value = 10 };
This answer gives takes a bit more space as it encodes the length of the ProtoInclude'd class instance (e.g. 1 byte for int and under < 125 byte strings). I am willing to live with this for the benefit of controlling the type statically.

C#: Enum anti-patterns [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
There has been talk of Enums in general violating Clean Code-principles, so I'm looking for people's favorite Enum anti-patterns and alternative solutions for these.
For example I've seen code like this:
switch(enumValue) {
case myEnum.Value1:
// ...
break;
case myEnum.Value2:
// ...
break;
}
It's one step better than switch-statements with magic strings, but this probably could have been solved better with a factory, a container or other pattern.
Or even old-school code like this:
if(enumValue == myEnum.Value1) {
// ...
} else if (enumValue == myEnum.Value2) {
// ...
}
What other anti-patterns and better implementations have you experienced with enums?
I think Enums are quite useful. I've written a few extensions for Enum that have added even more value to its use
First, there's the Description extension method
public static class EnumExtensions
{
public static string Description(this Enum value)
{
var entries = value.ToString().Split(ENUM_SEPERATOR_CHARACTER);
var description = new string[entries.Length];
for (var i = 0; i < entries.Length; i++)
{
var fieldInfo = value.GetType().GetField(entries[i].Trim());
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
description[i] = (attributes.Length > 0) ? attributes[0].Description : entries[i].Trim();
}
return String.Join(", ", description);
}
private const char ENUM_SEPERATOR_CHARACTER = ',';
}
This will allow me to define en enum like this:
public enum MeasurementUnitType
{
[Description("px")]
Pixels = 0,
[Description("em")]
Em = 1,
[Description("%")]
Percent = 2,
[Description("pt")]
Points = 3
}
And get the label by doing this: var myLabel = rectangle.widthunit.Description() (eliminating any need for a switch statement).
This will btw return "px" if rectangle.widthunit = MeasurementUnitType.Pixels or it will return "px,em" if rectangle.widthunit = MeasurementUnitType.Pixels | MeasurementUnitType.Em.
Then, there is a
public static IEnumerable<int> GetIntBasedEnumMembers(Type #enum)
{
foreach (FieldInfo fi in #enum.GetFields(BindingFlags.Public | BindingFlags.Static))
yield return (int)fi.GetRawConstantValue();
}
Which will let me traverse any enum with int based values and return the int values themselves.
I find these to be very useful in an allready useful concept.
It all depends what your trying to do with the enum.
If you are trying to stop your developers from passing magic numbers into your operations and you want to keep the data referential integrity intact with your DB then, YES! Use T4-Templates (using your ORM) to go to your MeasurementUnitTypes table and generate a enum with the ID, Name and Description columns matching the enum’ int, Enum_Name and Description Attribute (nice approach for additional field\data to enum #danijels) as suggested above. If you add a new Measurement Type to your MeasurementUnitTypes table you can just right click and run the T4-Template and the enum code is generated for that new row added in the table. I don’t like hard-coded data in my application that doesnt link to my DB hence the mention of the T4-Template approach. It is not extensible otherwise...what if some other external system wants to retrieve our Measurement Criteria used in our system, then it is hard-coded in the system and you can't expose it to the client via a service. That left there.
If the purpose is not data related and you have some logic assigned to a specific enum then NO! this violates the SOLID (Open close principle) as you would somewhere in your application apply a switch or bunch of Ifs to action the logic per enum, ALSO if you did it REALLY bad these switches or Ifs are all over the show....good luck adding a new enum... so it is not open for extension and closed for modification as you need to modify existing code, as per the SOLID principle.
If your choice is 2 then I suggest then to replace your enum with the following using the example from #danijels comment:
public interface IMeasurementUnitType
{
int ID { get; }
string Description { get; }
// Just added to simulate a action needed in the system
string GetPrintMessage(int size);
}
The above code defines the interface (code contract) that each measurement should adhere to. Now lets define Percentage and Pixel measurement :
public class PixelsMeasurementUnitType : IMeasurementUnitType
{
public int ID => 1;
public string Description => "Pixel";
public string GetPrintMessage(int size)
{
return $"This is a {Description} Measurement that is equal to {size} pixels of the total screen size";
}
}
public class PercentMeasurementUnitType : IMeasurementUnitType
{
public int ID => 2;
public string Description => "Persentage";
public string GetPrintMessage(int size)
{
return $"This is a {Description} Measurement that is equal to {size} persent of total screen size (100)";
}
}
So wee have defined two types, we would use them in code as follows:
var listOfMeasurmentTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => typeof(IMeasurementUnitType).IsAssignableFrom(p)
&& !p.IsInterface)
.ToList();
Here we grab all the TYPES that extends the IMeasurementUnitType interface and NOT the interface itself. Now we can use the Activator to create instances of the classes to populate our UI controls:
public IEnumerable<IMeasurementUnitType> GetInstantiatedClassesFromTypes(List<Type> types)
{
foreach (var type in types)
{
yield return (IMeasurementUnitType)Activator.CreateInstance(type);
}
}
You can change the code above to be generic for any type, AND NOW life happens and the client give a new measuring unit type called Point as a new requirement, I don't need to CHANGE ANY code, just add the new type (extend the code NOT modify). The new type will automatically be picked up in the application.
public class PointMeasurementUnitType : IMeasurementUnitType
{
public int ID => 3;
public string Description => "Point";
public string GetPrintMessage(int size)
{
return $"This is a {Description} Measurement that is equal to {size} points of total screen size";
}
}
a Good idea would be to cache your types for performance benefits upon starting your application or try and use a DI container of your choice.
Also, one can argue that somewhere in you application you would need to distinguish between types and I agree, however you want to keep apples with apples. So try as far as possible to apply the same principle used for this types. If this type is used in some sort of Graphics processor (for example) class then have a IGraphicsProcessor and have your concrete classes that differentiate between these types for example PersentageAndPixelGraphicsProcessor (that extends from IGraphicsProcessor) or if it distinguishes only one type call it PersentageGraphicsProcessor.
Sorry for the HUGE SA but I really like enum's however I feel when you trying to separate logic using a enums it is a STRONG anti-pattern.
comments welcome,
This isn't an answer, as much as contributing to a list of Enum anti-patterns.
During a code review this morning, I ran into a case similar to the following, all in the same class.
Two cases:
Before drinking
After drinking
..
public enum ListEnum
{
CategoryOne,
CategoryTwo,
CategoryThree,
CategoryFour
}
public class UIELementType
{
public const string FactoryDomain = "FactoryDomain";
public const string Attributes = "Attributes";
}
Using enums in not anti-pattern. In some books about refactoring this code is used to demonstrate how to replace it with polymorphism. It would be OK when you overuse enums in code.
I see having two switch statements as a symptom of non-OO design as explained further in this answer.

Categories

Resources