Programming exercise gone wrong - c#

So I have this simple (for others) exercise where i need to create a pharmacy and add to that 2 types of drugs. I have one class called Drugs which contains the attributes of the drugs:
public class drugattr
{
public int id;
public string drugName;
public string DrugDesc;
public int drugIntensity ;
public drugattr(int id, string drugName, string DrugDesc, int drugIntensity)
{
this.id = id;
this.drugName= drugName;
this.DrugDesc = DrugDesc;
this.drugIntensity = drugIntensity ;
}
}
Then i have a pharmacy class with the pharmacies attributes:
public class pharmacyatrr
{
public string PharmacyName;
public string PharmacyTown;
public List<drugattr> Atrributes= null; // the list with the drugs' attributes
public pharmacyatrr(string pharmacyName, string pharmacyTown, List<drugattr> atrributes)
{
this.PharmacyName = pharmacyName;
this.PharmacyTown = pharmacyTown;
this.Atrributes = atrributes;
}
and i have my main class where i need to create a pharmacy and assign to it a couple of drugs.
public class Program : pharmacyatrr
{
public Program(string PharmacyName, string PharmacyTown , List<drugattr> Atrributes) : base(PharmacyName, PharmacyTown , Atrributes)
{
this.PharmacyName = pharmacyName;
this.PharmacyTown = pharmacyTown;
this.Atrributes = atrributes;
}
static void Main(string[] args)
{
drugattr drugA = new drugattr(1, "DrugA_Name", "Very STrong", 20);
drugattr drugB = new drugattr(2, "DrugB_Name", "Mild Strong", 8);
pharmacyatrr pharmacy1 = new pharmacyatrr("PharmacyName", "Town", drugA); // the problem is here
}
}
So if I try to add drugB i get the expected error that it can only accept 3 parameters.
If i create a pharmacy2 with the same name and town but with drugB that wouldn't create a new pharmacy?
I need one pharmacy to have multiple drug entries...
any tips on how to solve this? I am fairly new to C# and programming so please don't go harsh on me!

This should work. Pretty much what everyone has said, but just the complete code.
Drugs Class
class DrugAttribute
{
public int id;
public string drugName;
public string drugDescription;
public int drugIntensity;
public DrugAttribute(int id, string drugName, string drugDescription, int drugIntensity)
{
this.id = id;
this.drugName = drugName;
this.drugDescription = drugDescription;
this.drugIntensity = drugIntensity;
}
}
And the Pharmacy Class
class PharmacyAtrribute
{
public string pharmacyName;
public string pharmacyTown;
public List<DrugAttribute> drugList = null;
public PharmacyAtrribute(string pharmacyName, string pharmacyTown, List<DrugAttribute> drugList)
{
this.pharmacyName = pharmacyName;
this.pharmacyTown = pharmacyTown;
this.drugList = new List<DrugAttribute>(drugList);
}
}
And the main class
class Program : PharmacyAtrribute
{
public Program(string pharmacyName, string pharmacyTown, List<DrugAttribute> drugList) : base(pharmacyName, pharmacyTown, drugList)
{
this.pharmacyName = pharmacyName;
this.pharmacyTown = pharmacyTown;
this.drugList = new List<DrugAttribute>(drugList);
}
static void Main(string[] args)
{
DrugAttribute drugA = new DrugAttribute(1, "DrugA_Name", "Very Strong", 20);
DrugAttribute drugB = new DrugAttribute(2, "DrugB_Name", "Mild Strong", 8);
List<DrugAttribute> listOfDrugs = new List<DrugAttribute>{ drugA, drugB };
PharmacyAtrribute pharmacy1 = new PharmacyAtrribute("PharmacyName", "Town", listOfDrugs);
}
}
I'm sure you may have noticed I changed some of the names. I'll just give you a couple of helpful tips regarding naming conventions. For Classnames, Microsoft encourages use of the Pascal capitalization style. So in your case, drugattr would be DrugAttr. For variables and attributes, Camel Case is encouraged. So
public string PharmacyName;
public string PharmacyTown;
public List<drugattr> Atrributes= null;
should become
public string pharmacyName;
public string pharmacyTown;
public List<drugattr> atrributes= null;
For more about naming conventions, have a look at this https://msdn.microsoft.com/en-us/library/x2dbyw72(v=vs.71).aspx
And with names, it's good to be as descriptive as possible, so calling your class DrugAttributes might be a good idea. Anyone who is reading your code will know exactly what it's about even without comments (Although comments are a must too).
Even if it's just a simple learning exercise, it's always good to practice with conventional styles.

You need to create a list of drugs to match your List parameter in the pharmacyattr constructor.
Create a new list like:
List<drugattr> drugList = new List<drugattr>();
And add to the list like this:
drugList.Add(drugA);
You can then create your pharmacy with the slight adjustment of:
pharmacyatrr pharmacy1 = new pharmacyatrr("PharmacyName", "Town", drugList);

var drugs = new List<drugattr> { drugA, drugB };
pharmacyatrr pharmacy1 = new pharmacyatrr("PharmacyName", "Town", drugs);

Related

given a unit test that make sure that prevent wrong-assigned values in a class argument, how to write a method that takes that into account?

I'm introduced recently to Test Driven Development. However, I am having a hard time understanding it. The following unit test is a given:
public void Setup()
{
invoicePosition = new InvoicePosition{
Customer = new Customer(),
ItemIdentifier = 0,
ItemName = "SpringRoll",
Orders = 2,
SingleUnitPrice = 3.50m
};
pairs = new KeywordPair[]{
new KeywordPair(new Keyword("ItemNumber"),invoicePosition.ItemIdentifier.ToString()),
new KeywordPair(new Keyword("ItemName"), invoicePosition.ItemName),
new KeywordPair(new Keyword("CustomerName"), invoicePosition.Customer.Name),
new KeywordPair(new Keyword("AmountOrdered"), invoicePosition.Orders.ToString()),
new KeywordPair(new Keyword("NetPrice"), invoicePosition.SingleUnitPrice.ToString())
};
}
[Test]
public void Invoice_CreateOrderOrderedInput_Valid(){
var invoice = InvoicePosition.CreateFromPairs(pairs);
Assert.AreEqual(invoicePosition.ItemIdentifier, invoice.ItemIdentifier);
Assert.AreEqual(invoicePosition.ItemName.GetType(), invoice.ItemName.GetType());
Assert.AreEqual(invoicePosition.Customer.Name, invoice.Customer.Name);
Assert.AreEqual(invoicePosition.Orders, invoice.Orders);
Assert.AreEqual(invoicePosition.SingleUnitPrice, invoice.SingleUnitPrice);
}
Please note that Keyword and Keyword structs are as follows:
public struct Keyword
{
private string keyword;
private KeywordTypes type;
public Keyword(string keyword, KeywordTypes Type = KeywordTypes.String){
this.keyword = keyword;
this.type = Type;
}
public struct KeywordPair
{
public Keyword Key;
public string Value;
public KeywordPair(Keyword key, string value)
{
this.Key = key;
this.Value = value;
}
}
now I have written the following project for the previous unit test:
namespace SimpleShop
public class InvoicePosition
{
public uint ItemIdentifier = 0;
public string ItemName = "";
public uint Orders = 0;
public decimal SingleUnitPrice = 0.0m;
public Customer Customer;
public KeywordPair[] Pairs = new KeywordPair[0];
public static InvoicePosition CreateFromPairs(KeywordPair[] pairs)
{
var invoice = new InvoicePosition();
invoice.Pairs = pairs;
return invoice;
}
}
I need to write code that accounts for wrong serializations. for example, what if pairs is introduced to the program as follows:
pairs[3] = new KeywordPair(new Keyword("AmountOrdered"), "+%&/" + invoicePosition.Orders.ToString());
pairs[4] = new KeywordPair(new Keyword("NetPrice"), invoicePosition.SingleUnitPrice.ToString() +
"%&öä/");
thank you, any help would be great.
Given the test Invoice_CreateOrderOrderedInput_Valid, the InvoicePosition suggested in the OP does not pass the test. By using Visual Studio's various refactoring tools, something like this is the simplest thing that could possibly work:
public class InvoicePosition
{
public Customer Customer { get; set; }
public int ItemIdentifier { get; set; }
public string ItemName { get; set; }
public int Orders { get; set; }
public decimal SingleUnitPrice { get; set; }
public static InvoicePosition CreateFromPairs(KeywordPair[] pairs)
{
return new InvoicePosition
{
ItemName = "",
Customer = new Customer(),
Orders = 2,
SingleUnitPrice = 3.5m
};
}
}
The CreateFromPairs implementation is clearly not the full or correct implementation, but it passes all tests. The challenge with TDD is to figure out which test to write next.
TDD works best if you can move forward in as small steps as possible. You might want to consider the Transformation Priority Premise. Which part of the incorrect implementation would you first like to address?
Perhaps you're unhappy that ItemName is hard-coded to the empty string. How can you write a new test that encourages you to make the implementation more general?
I'd write another test that keeps everything from the first test constant, except the ItemName value.
The way the test is currently structured, with its big Setup method, makes that inconvenient. I recommend that you look into writing parametrised tests instead.

C# Lists - do I use Class Methods (Get/ Set etc) again once the data is in a list?

A quick question on OOP. I am using a list together with a class and class constructor. So I use the class constructor to define the data set and then add each record to my list as the user creates them.
My questions is once the data is in the list and say I want to alter something is it good practice to find the record, create an instance using that record and then use my class methods to do whatever needs doing - and then put it back in the list?
For example below I have my class with constructor. Lets say I only want the system to release strCode if the Privacy field is set to public. Now just using Instances I would use for example Console.WriteLine(whateverproduct.ProductCode) but if the record is already in a list do i take it out of the list - create an instance and then use this method?
class Product
{
private String strCode;
private Double dblCost;
private Double dblNet;
private String strPrivacy;
public Product(String _strCode, Double _dblCost, Double _dblNet, String _strPrivacy)
{
strCode = _strCode;
dblCost = _dblCost;
dblNet = _dblNet;
strPrivacy = _strPrivacy;
}
public string ProductCode
{
get
{
if (strPrivacy == "Public")
{
return strCode;
}
else
{
return "Product Private Can't release code";
}
}
}
Lets say we have the following:
public class Test
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Amount { get; set; }
private string _test = "Some constant value at this point";
public string GetTest()
{
return _test;
}
public void SetTest()
{
//Nothing happens, you aren't allow to alter it.
//_test = "some constant 2";
}
}
public class Program
{
public static void Main(string[] args)
{
List<Test> listOfTest = new List<Test>()
{
new Test() {Id = 0, Name = "NumberOne", Amount = 1.0M},
new Test() {Id = 1, Name = "NumberTwo", Amount = 2.0M}
};
Test target = listOfTest.First(x => x.Id == 0);
Console.WriteLine(target.Name);
target.Name = "NumberOneUpdated";
Console.WriteLine(listOfTest.First(x => x.Id == 0).Name);
Console.WriteLine(listOfTest.First(x => x.Id == 0).GetTest());//This will alsways be "Some constant value at this point";
Console.ReadLine();
}
}
Technically you could do away with the SetTest method entirely. However, I included it to demonstrate, what it would look like, if you wanted to alter _test.
You don't want to ever create a new instance of a class, you already have an instance of. you can just alter the class where it is allowed by the author of the class, where you need to. And keep that class reference for as long as you need it. Once you are done, the reference will be garbage collected, once the program finds no active reference to your object(instance).

Enumeration Objects (Strings) in Entity Framework

I am building a model with Entity Framework and purchased responsive CSS.
The built in fixed icons comes with CSS. Like as follows (Name and Icon Class Value)
I need a way to keep the names of icons as fixed enums to access it from the VS intellisense. Currently we can't store as a entity table in entity framework (as it require relationship with tables difficult to maintain) and enum doesn't allows string type.
Code that did not work:
public sealed class IconType
{
public static readonly IconType Rupee_Icon = new IconType("rupee-icons");
public static readonly IconType Doller_Icon = new IconType("doller-icon");
private IconType(int EnumID,string EnumObjectValue)
{
IconValue = EnumObjectValue;
}
public string IconValue { get; private set; }
}
More code that did not work (CSS class names contains whitespaces like ui bell icon):
public enum Icon
{
NotSet=0,
Idea Icon=1,
Bell Icon =2
}
Is there any other ways to use names / objects as enums or constants in EF for easy intellisense in Visual Studio?
You could:
Omit the white spaces in the enums:
public enum Icon
{
NotSet = 0,
IdeaIcon = 1,
BellIcon = 2
}
Add a description or name (Or even some custom attribute) attributes to the enums:
public enum Icon
{
NotSet = 0,
[Description("ui idea icon")]
IdeaIcon = 1,
[Description("ui bell icon")]
BellIcon = 2
}
When needed get the description name. Example method to get the description attribute value:
public static string GetDescription<T>(this T enumerationValue)
where T : struct, IConvertible
{
var type = enumerationValue.GetType();
if (!type.IsEnum)
{
throw new ArgumentException("EnumerationValue must be of Enum type", "enumerationValue");
}
// Tries to find a DescriptionAttribute for a potential friendly name for the enum
var memberInfo = type.GetMember(enumerationValue.ToString(CultureInfo.InvariantCulture));
if (memberInfo.Length > 0)
{
var attributes = memberInfo[0].GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Length > 0)
{
// Pull out the description value
return ((DescriptionAttribute)attributes[0]).Description;
}
}
// If we have no description attribute, just return the ToString of the enum
return enumerationValue.ToString(CultureInfo.InvariantCulture);
}
Did you consider using string constants?
public static class IconType
{
public const string RUPEE_ICON = "rupee-icon";
public const string DOLLER_ICON = "doller-icon";
// ...
}
Store the icon's as plain old objects. Why make use of entity framework at all?
public static class Icons
{
public enum Type
{
IdeaIcon = 1,
BellIcon =2
}
public static Icon Get(Type type)
{
return IconCollection.Single(icon => icon.Type == type);
}
static IEnumerable<Icon> IconCollection
{
get
{
return new List<Icon>
{
new Icon(Type.IdeaIcon, "Idea Icon", "icon idea-icon"),
new Icon(Type.BellIcon, "Bell Icon", "icon bell-icon"),
};
}
}
public class Icon
{
public Icon(Type type, string description, string cssClass)
{
Type = type;
Description = description;
CssClass = cssClass;
}
public Type Type { get; private set; }
public string Description { get; private set; }
public string CssClass { get; private set; }
}
}
Use in code:
public class Class1
{
public void Method1()
{
var ideaIcon = Icons.Get(Icons.Type.IdeaIcon);
var x = ideaIcon.CssClass;
var y = ideaIcon.Description;
var bellIcon = Icons.Get(Icons.Type.BellIcon);
// etc...
}
}
Razor view:
#Icons.Get(Icons.Type.BellIcon).CssClass
If you needed to enumerate over the icon collection you could easily add another static accessor to the Icons class.

How do I retrieve data from a list<> containing class objects

I want to retrieve data from a list I created that contains class objects via a foreach but I'm not able to.
Can somebody please tell me what's missing in my code?
I have a class Recipes.cs that contains the following code:
public class Recipe
{
string _oveskrift;
int _recipe_id;
string _opskrift;
int _kcal;
public Recipe(string overskrift, int recipe_id, string opskrift,int kcal)
{
_oveskrift = overskrift;
_recipe_id = recipe_id;
_opskrift = opskrift;
_kcal = kcal;
}
}
public class Recipes
{
public List<Recipe> CreateRecipeList()
{
Recipe opskrift1 = new Recipe("Cornflakes med Chili",1,"4 kg cornflakes bages", 420);
Recipe opskrift2 = new Recipe("Oksemørbrad",2,"Oksemørbrad steges i baconfedt", 680);
Recipe opskrift3 = new Recipe("Tun i vand",3,"Dåsen åbnes og tunen spises", 120);
List<Recipe> Recipelist = new List<Recipe>();
Recipelist.Add(opskrift1);
Recipelist.Add(opskrift2);
Recipelist.Add(opskrift3);
return Recipelist;
}
}
I call CreateRecipeList() from another class calculator.cs and the code looks like this:
private int FindRecipes()
{
List<Recipe> Rlist = new List<Recipe>();
// CREATE THE CLASS AND ADD DATA TO THE LIST
Recipes r = new Recipes();
Rlist = r.CreateRecipeList();
int test = 0; // used only for test purposes
foreach(var rec in Rlist)
{
rec.????
test++;
}
return test;
}
I would presume that I should be able to dot my way into rec."the class object name"."the value"
But nothing happens!.
All I get is the option to rec.Equals, rec.GetHashcod ect. which is clearly wrong.
For the record I have also tried:
foreach(Recipe rec in Rlist)
{
rec.????
test++;
}
But that doesn't work either.
The Int test are only there for test purposes.. and it return 3.. so the list does contain the correct information.
Please show us the code for the Recipe class. Besides that, you're most of the way there...
foreach(Recipe rec in Rlist)
{
string str = rec.<PropertyName>;
}
You need to set the proper access modifiers for the members in your Recipe class.
public : Access is not restricted.
protected : Access is limited to the containing class or types derived from the containing class.
Internal : Access is limited to the current assembly.
protected internal: Access is limited to the current assembly or types derived from the containing class.
private : Access is limited to the containing type.
By default, the members of your Recipe class will have the private access modifier.
string _oveskrift;
int _recipe_id;
string _opskrift;
int _kcal;
is:
private string _oveskrift;
private int _recipe_id;
private string _opskrift;
private int _kcal;
Maybe you want to modify your member access as follows, in order to set the values of the members only inside the class code. Any attempt to set their values outside the Recipe class will fail, as the set is private. The get remains public, which makes the value available for reading.
public class Recipe
{
string _oveskrift;
int _recipe_id;
string _opskrift;
int _kcal;
public string Oveskrift
{
get
{
return _oveskrift;
}
private set
{
_oveskrift=value;
}
}
public int RecipeId
{
get
{
return _recipe_id;
}
private set
{
_recipe_id = value;
}
}
public string Opskrift
{
get
{
return _opskrift;
}
private set
{
_opskrift = value;
}
}
public int Kcal
{
get
{
return _kcal;
}
private set
{
_kcal = value;
}
}
public Recipe(string overskrift, int recipe_id, string opskrift, int kcal)
{
_oveskrift = overskrift;
_recipe_id = recipe_id;
_opskrift = opskrift;
_kcal = kcal;
}
}
Also, please read as soon as possible the following MSDN article: Capitalization Conventions. And also, this one: C# Coding Conventions (C# Programming Guide).

Enumerate with return type other than string?

Since enumeration uses integers, what other structure can I use to give me enum-like access to the value linked to the name:
[I know this is wrong, looking for alternative]
private enum Project
{
Cleanup = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1"),
Maintenance = new Guid("39D31D4-28EC-4832-827B-A11129EB2"),
Upgrade = new Guid("892F865-E38D-46D7-809A-49510111C1"),
Sales = new Guid("A5690E7-1111-4AFB-B44D-1DF3AD66D435"),
Replacement = new Guid("11E5CBA2-EDDE-4ECA-BDFD-63BDBA725C8C"),
Modem = new Guid("6F686C73-504B-111-9A0B-850C26FDB25F"),
Audit = new Guid("30558C7-66D9-4189-9BD9-2B87D11190"),
Queries = new Guid("9985242-516A-4151-B7DD-851112F562")
}
EDIT 2014-07-20
This is a newer answer to this question. Using the Attribute class with a helper method, define the extra attributes needed on your enum.
public enum MultiValueEnum
{
[FooAttribute("alpha", 20d, true)]
First,
[FooAttribute("beta", 40.91d, false)]
Second,
[FooAttribute("gamma", 1.2d, false)]
Third,
}
public class FooAttribute : Attribute
{
internal FooAttribute(string name, double percentage, bool isGood)
{
this.Name = name;
this.Percentage = (decimal)percentage;
this.IsGood = isGood;
}
public string Name { get; private set; }
public decimal Percentage { get; private set; }
public bool IsGood { get; private set; }
}
public static TAttribute GetAttribute<TAttribute>(this Enum value)
where TAttribute : Attribute
{
var type = value.GetType();
var name = Enum.GetName(type, value);
return type.GetField(name)
.GetCustomAttributes(false)
.OfType<TAttribute>()
.SingleOrDefault();
}
Which makes it this easy:
MultiValueEnum enumVar = MultiValueEnum.First;
var enumStringValue = enumVar.GetAttribute<FooAttribute>().Name;
var enumValueDecimal = enumVar.GetAttribute<FooAttribute>().Percentage;
var enumBool = enumVar.GetAttribute<FooAttribute>().IsGood;
Otherwise you could create a custom Attribute for your enum, which can hold the Guid.
Something alongside these lines:
class EnumGuid : Attribute
{
public Guid Guid;
public EnumGuid(string guid)
{
Guid = new Guid(guid);
}
}
And you'd then use it like so:
enum Project
{
[EnumGuid("2ED3164-BB48-499B-86C4-A2B1114BF1")]
Cleanup = 1,
[EnumGuid("39D31D4-28EC-4832-827B-A11129EB2")]
Maintenance = 2
// and so forth, notice the integer value isn't supposed to be used,
// it's merely there because not assigning any value is a performance overhead.
}
And finally you could (I always do this) create an extension for easily getting the guid:
static Guid GetEnumGuid(this Enum e)
{
Type type = e.GetType();
MemberInfo[] memInfo = type.GetMember(e.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(EnumGuid),false);
if (attrs != null && attrs.Length > 0)
return ((EnumGuid)attrs[0]).Guid;
}
throw new ArgumentException("Enum " + e.ToString() + " has no EnumGuid defined!");
}
So in the end all you have to with your enums is:
Guid guid = Project.Cleanup.GetEnumGuid();
I use this approach to attach descriptions to enums, typically longer strings containing spaces, which thus cannot be used as names.
I've seen this method (struct) used by SubSonic to store Column and Table names.
internal struct Project
{
public static Guid Cleanup = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1");
public static Guid Maintenance = new Guid("39D31D4-28EC-4832-827B-A129EB2");
public static Guid Upgrade = new Guid("892F865-E38D-46D7-809A-49510111C1");
public static Guid Sales = new Guid("A5690E7-1111-4AFB-B44D-1DF3AD66D435");
public static Guid Replacement = new Guid("11E5CBA2-EDDE-4ECA-BD63-B725C8C");
public static Guid Modem = new Guid("6F686C73-504B-111-9A0B-850C26FDB25F");
public static Guid Audit = new Guid("30558C7-66D9-4189-9BD9-2B87D11190");
public static Guid Queries = new Guid("9985242-516A-4151-B7DD-851112F562");
}
EDIT:- Thanks for commenting on deficiencies in code. In first place it will compile if the Guid strings are not invalid. As for not create instances to access variables yes they need to be public static
I would probably go the dictionary route on this one. Have a lookup table basically:
public class GuidMapper
{
private Dictionary<GuidTypes, Guid> mGuidMap = new Dictionary<GuidTypes, Guid>();
public enum GuidTypes: int
{
Cleanup,
Maintenance,
Upgrade,
Sales,
Replacement,
Modem,
Audit,
Queries
}
public GuidMapper()
{
mGuidMap.Add(GuidTypes.Cleanup, new Guid("2ED31640-BB48-499B-86C4-A2B1114BF100"));
mGuidMap.Add(GuidTypes.Maintenance, new Guid("39D31D40-28EC-4832-827B-A11129EB2000"));
mGuidMap.Add(GuidTypes.Upgrade, new Guid("892F8650-E38D-46D7-809A-49510111C100"));
mGuidMap.Add(GuidTypes.Sales, new Guid("A5690E70-1111-4AFB-B44D-1DF3AD66D435"));
mGuidMap.Add(GuidTypes.Replacement, new Guid("11E5CBA2-EDDE-4ECA-BDFD-63BDBA725C8C"));
mGuidMap.Add(GuidTypes.Modem, new Guid("6F686C73-504B-1110-9A0B-850C26FDB25F"));
mGuidMap.Add(GuidTypes.Audit, new Guid("30558C70-66D9-4189-9BD9-2B87D1119000"));
mGuidMap.Add(GuidTypes.Queries, new Guid("99852420-516A-4151-B7DD-851112F56200"));
}
public Guid GetGuid(GuidTypes guidType)
{
if (mGuidMap.ContainsKey(guidType))
{
return mGuidMap[guidType];
}
return Guid.Empty;
}
}
If you need proper enum-like semantics and type-safety then you can use a pattern like this.
(You could flesh it out further if you require extras like conversion operators, GetUnderlyingType, ToString etc. If you wanted to re-use the pattern for multiple enum-like classes with different underlying types then you could move any common code into a generic, abstract base class.)
Project x = Project.Cleanup;
Project y = Project.Cleanup;
Project z = Project.Maintenance;
Console.WriteLine(x == y); // True
Console.WriteLine(x == z); // False
Console.WriteLine(x.Value); // 47801daa-7437-4bfe-a240-9f7c583018a4
// this line will cause a compiler error
Console.WriteLine(x == new Guid("47801daa-7437-4bfe-a240-9f7c583018a4"));
// ...
public class Project
{
private Project(Guid v) { Value = v; }
public Guid Value { get; private set; }
public static readonly Project Cleanup =
new Project(new Guid("47801daa-7437-4bfe-a240-9f7c583018a4"));
public static readonly Project Maintenence =
new Project(new Guid("2548a7f3-7bf4-4533-a6c1-dcbcfcdc26a5"));
public static readonly Project Upgrade =
new Project(new Guid("ed3c3e73-8e6a-4c09-84ae-7f0876d194aa"));
}
When confronted with this kind of problem I used structs with consts as public members:
public struct FileExtensions
{
public const string ProcessingExtension = ".lck";
public const string ProcessedExtension = ".xml";
public const string FailedExtension = ".failed";
public const string CsvExtension = ".csv";
}
You could create a static class that just contains constant values.
For example:
internal static class Project
{
public static readonly Guid Cleanup = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1");
public static readonly Guid Maintenance = new Guid("39D31D4-28EC-4832-827B-A11129EB2");
public static readonly Guid Upgrade = new Guid("892F865-E38D-46D7-809A-49510111C1");
}
This way the class acts simply as a container and object cannot be created from it.
In VB this would be a Module:
Friend Module Project
Public Shared ReadOnly Cleanup As Guid = New Guid("2ED3164-BB48-499B-86C4-A2B1114BF1")
Public Shared ReadOnly Maintenance As Guid = New Guid("39D31D4-28EC-4832-827B-A11129EB2")
Public Shared ReadOnly Upgrade As Guid = New Guid("892F865-E38D-46D7-809A-49510111C1")
End Module
The enum type can only support the integral types (except char) as its value. You could however use something like a Dictionary to do lookups of a a name to a value.
Dictionary<Guid> lookup = new Dictionary<Guid>();
lookup["Cleanup"] = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1");
lookup["Maintenance"] = new Guid("39D31D4-28EC-4832-827B-A11129EB2");
lookup["Upgrade"] = new Guid("892F865-E38D-46D7-809A-49510111C1");
// etc...
Another alternative is to have a series of readonly values in a static class.
public static class Guids
{
public static readonly Guid Cleanup = new Guid("2ED3164-BB48-499B-86C4-A2B1114BF1");
public static readonly Guid Maintenance = new Guid("39D31D4-28EC-4832-827B-A11129EB2");
public static readonly Guid Upgrade = new Guid("892F865-E38D-46D7-809A-49510111C1");
}

Categories