Architecture for achievements / badges - c#

There's a lot of questions already about coding a badge system similar to SO, my question is different. Assume I have a web page system, badges / achievements, stored in the DB as a row with the achievement key (id), user id, and any other data.
My simple question is, where should I store the badge ID? I have one class per achievement with all the data and methods for testing if it has been earned. I imagine I may have dozens or hundreds at some point. I want the IDs to be used hard coded only once, and in one concise place, so I have no chance of accidentally changing them or mixing them up.
I could hard code them in the class, like
public int Key { get { return 15; } } // I'm calling it Key, not ID
but if I split my achievements among multiple files I don't want to have to run around looking for the highest Key when I add a new one and risk a mistake.
I could put them in some dictionary in another class...
public class AchievementSet
{
private Dictionary<int, Achievement> _achievements;
public AchievementSet()
{
_achievements = new Dictionary<int, Achievement>()
{
{ 1, new SomethingAchievement() }
};
}
}
But now the class itself doesn't know its own key, and it needs to (or does it?) If I passed it into the constructor now I risk mismatching the numbers.
Any recommendations?

In the context of Stack Overflow, I'd imagine each badge has properties such as:
Id, Name, Class (Bronze, Silver or Gold) and Description etc.
You mention that you currently have a class for each badge/achievement, each with appropriate checks for conditions on which it would be awarded.
The reason I'm suggesting you move away from the model you're looking at now (one class per achievement) is because you're going to continue to face huge problems down the road when you're navigating through 200 different classes looking for that one ID you can't recall.
By storing your badges in the table, your data is all in one logical place and not scattered across your application.
In answer to the question: So do you disagree with the accepted answer to: stackoverflow.com/questions/3162446/
Not necessarily, and I like this idea more than my earlier proposal for a single class that would check all the badges based on their ID.
Despite its name, I believe RexM is not defining the CommenterBadge itself in that file and should have named it CommenterBadgeJob. (You'll notice it has none of the traits I've defined in my answer and inherits from BadgeJob). The obvious question is "How does each badge job know which BadgeId it corresponds to?"
I would have an additional unique field in my Badge called BadgeJob by which you could lookup a badge.
enum BadgeClass {Bronze, Silver, Gold}
//This class would be inherited from the database.
public class Badge
{
public int Key {get;set;}
public string Name {get;set;}
public BadgeClass Class {get;set;}
public string BadgeJob {get;set;}
public string Description {get;set}
}
I would modify his code as follows:
public class CommenterBadgeJob : BadgeJob
{
public Badge commenter_badge {get;set;}
public CommenterBadgeJob() : base()
{
//Lookup badge
string badge_job_name = this.GetType().Name;
commenter_badge = db.Badges.Where(n=>n.BadgeJob == badge_job_name).Single();
}
protected override void AwardBadges()
{
//select all users who have more than x comments
//and dont have the commenter badge
//add badges
}
//run every 10 minutes
protected override TimeSpan Interval
{
get { return new TimeSpan(0,10,0); }
}
}

How about using an enum ?
public enum BadgeTypes
{
GoodAnswer = 1,
Commenter = 2,
Teacher = 3,
//...
}
Each BadgeJob could have a BadgeType property which would be used to populate the badge id when inserting an achievement during AwardBadges() (enum values can be persisted to integers).
I see no necessity for having one class per achievement. BadgeJob's contain all badge attribution logic and BadgeTypes suffice to represent the different badges.

Related

Entity Framework, how to make this more generic to write less code

So, I am writing a program, and getting my data using EF 6.
Basically, I though the simplest approach would be to have one class like this:
public class DataRetriever
{
public List<TEntity> GetAll<TEntity>() where TEntity : class
{
using (var Db = new Entity())
{
return Db.Set<TEntity>().ToList();
}
}
}
So then, you care start creating other classes on the basis of specifying which data you want to be collected. So say I have a list of carnival rides and one method is to get a single ride or something. SO then I would have the following:
public class SelectedRide
{
int RideId { get; set; }
string RideName { get; set; }
string DomValue { get; set; }
public SelectedRide(DataRetriever Retriever)
{
var Records = Retriever.GetAll<vwRideList>();
var Record = from x in Records
where x.RideId == RideId
select x;
RideName = Record.Single().RideName;
DomValue = Record.Single().DomValue;
}
}
Ride ID being an identity.
So then one could say that if another class like say we had multiple parks where rides were, could be public class SelectedPark it would have the same logic, but in the Retriever.GetAll<vwParkList>(); The ride list is now the park list. And so on.
I can't tell if this is quickly going to get out of hand if I say had 50 separate types of retrieving that needed to be done. Granted, I won't as I know the total scope of this program, but WHAT IF.
I've seen stuff like the repo pattern as well, but I can't tell if that's somewhat of a waste of time or not. I can't tell what I am getting out of it. This seemed to keep it generic enough that I am not writing the context in a million different places.

Class design best way to handle multi-value options and the selected value?

What's the best way to design a class (or classes) that can hold the potential values of item, as well as the one the user actually selected? I've come across this problem before and always feel like I'm missing a core class design feature.
Right now I usually do something like the following
class MultiChoice
Name (I.e. Box Size)
Default Value ("22x15")
PotentialValues ({"10x10","20x20","22x15"})
But that doesn't handle the actual value the user selected, so I add that in.
class MultiChoice
Name (I.e. Box Size)
Default Value ("22x15")
PotentialValues ({"10x10","20x20","22x15"})
SelectedValue
That doesn't feel right though, because when I construct a drop-down I'm filling in stuff with SelectedValue = null. Then when I store the data, I'm storing all the options too, which I don't need.
Is there a better way to handle this with an interface or other language construct? I always feel like I'm missing something blatantly obvious here.
You really have two separate entities here:
MultiChoiceQuestion
MultiChoiceAnswer
Create two separate classes to represent these two separate concepts.
ASP.NET MVC has the SelectList class. While you might not actually be working in ASP.NET MVC, it seems clear that Microsoft felt that the concept of "backing class for a dropdown" was universal enough to warrant its own class.
In whatever you consider the "Model" (that part of your program containing the business domain classes and business logic), there will always exist database tables that serve as lookups for these dropdowns.
tblCountries
CountryID PK
CountryCode string
FullName string
In your ViewModel, there will be a corresponding list of countries from which you can populate the dropdown:
public class InvoiceViewModel
{
...
public int CountryID { get; set; }
public SelectList Countries { get; set; }
// or
public List<Country> Countries { get; set; }
...
}
Of course, by the time you get to the UI, the actual dropdown contains enough plumbing to hold both the select list and the selected value.
You really only need a single Value field. Set it to whatever you want in the constructor (so it's defaulted when the object is created). You can also change your 'potential values' to be static, so it's the same for the entire class.
public class Box
{
public string Value { get; set; }
public static List<string> AllowedValues { get; private set; }
public Box()
{
AllowedValues.AddRange(new string[]{"10x10","20x20","22x15"});
Value = AllowedValues.First();
}
}
Then when a user changes the value, simply update it.
Box thisBox = new Box();
string val = "22x15";
if (Box.AllowedValues.Contains(val))
thisBox.Value = val;

Modelling contact details for a person / customer

I was wondering if there was a more elegant way in managing contact details for an individual. Forget the SQL side of things for a moment, I am intrigued in how one would perhaps attempt to drive this via a DDD approach.
I was fooling around with some code in an effort to get comfortable with DDD as a whole and came up with the following which seems awful.
Firstly, I have an object called Person (simplified for the purpose of this post) where I envision methods to add and essentially manage different methods of communicating an individual.
public class Person
{
public Person()
{
this.ContactDetails = new List<ContactDetails>();
}
public void AssociateContactDetails(ContactDetails contactDetails)
{
var existingContactDetails = this.ContactDetails.FirstOrDefault(x => x.ContactType == contactDetails.ContactType);
if (existingContactDetails != null)
{
this.ContactDetails.Remove(existingContactDetails);
}
this.ContactDetails.Add(contactDetails);
}
public IList<ContactDetails> ContactDetails { get; private set; }
}
Two approaches spring to mind. One where I have a fairly simple object like the one below which is quite generic (using the term loosely).
public enum ContactType
{
Email, Telephone, Mobile, Post
}
public class ContactDetails
{
private readonly ContactType contactType;
private readonly string value;
public ContactDetails(ContactType contactType, string value)
{
this.contactType = contactType;
this.value = value;
}
public ContactType ContactType
{
get { return this.contactType; }
}
public string Value
{
get { return this.value; }
}
}
But then I put myself into a corner with this approach as although it works well for trivial items such as email and telephone, when it comes to something like postal a string doesn't quite cut it. Therefore, after this I am heading towards the approach of having each mechanism of communication to represented by its own type, i.e.:
public class Post
{
public Address PostalAddress { get; set; }
}
public class Mobile
{
public string MobileNo { get; set; }
}
public class Telephone
{
public string AreaCode { get; set; }
public string TelephoneNo { get; set; }
}
public class Email
{
public string EmailAddress { get; set; }
}
Each type can then represented as a collection or single instance in the Person class? Seems long winded however is perhaps more readable and maintainable.
The question I guess is if there is a more elegant way in implementing such a feature and whether someone can point me in the direction of a good example similar to this. I imagine this is a common thing / problem to overcome.
Cheers, DS.
We know for sure what are the contact methods "email, "phone" and "address", so having identified those what we have to do first is to model those concepts taking into account what they really are. Let's take "email" as example and see what it really is in order to model it properly. It is a value object (an immutable object) that once created it will never change just as an integer number is an immutable object as well. The difference is that for modelling an integer number we can use the int type provided by any programming language, but the question is what class do we use for modelling en Email? Most of people would use a String instance to model an Email, but is this OK? In order to answer it let's see what is the protocol (the set of messages) a String object knows to response: "charAt(anIndex), replace(aString, anotherString), etc... ". Imagine that if we model an email by using a String class we could ask the email "replace(aString, anotherString)". That sounds weird, that message should not be part of the behavior an email should expose to other objects. Also so so important we said an email is immutable to it cannot expose behavior that at the end change it state. So it makes visible that we need to create a whole new abstraction to model an email and what is it? The Email class finally comes in!!! I know you suggested it but I just wanted to let you see why we need an Email class created.
First of all this is DDD (object oriented) so FORGET avoid setters and getters. In the email class you created you expose a setter method meaning that you can change the email and it contradicts with the nature of what an email is (immutable). An email is immutable from the momento it is created:
Email.fromString("monicalewinsky#gmail.com");
that is the same as doing
new Email("monicalewinsky#gmail.com");
The fromString method is a factory method that adds semantic to our domain model. This is very common in smalltalk instead of calling the constructor directly. Are we done??? Not at all. An email instance should be created as long as it is valid so the email class should assert the string from which is created is valid:
Email(String anEmailStringRepresentation) {
assertIsValid(anEmailStringRepresentation);
}
assert is valid should verify it is actually an email string representation. This is that is has only one # character, its local part is valid and then its domain part is valid. You can check the wikipedia for email address to understand better how it is composed.
Remember always that programming is a learning process, as long as we understand a domain better and better we reflect that domain in the code and it always must be consistent with the real world! Our Email class should look like more or less like:
class Email {
String value;
Email(aString) {
value = aString;
}
public String getLocalPart()
public String getDomainPart()
public String asString()
public boolean equals(anObject)
public static Email fromString(aString)
}
That's it. It happens the same with PhoneNumber. It is also an inmmutable object and you should create a class with its own protocol. Remember never use set/get as you showed up if we are doing DDD. I don't think you need two value objects Telephone and Mobile since those are polymorphic objects and you could model a mobile phone number or a home phone number with the TelephoneNumber abstraction. It's like modelling a credit card. At the end you will end up and understand that the class CreditCard is enough and a better design than having several class such as Visa, MasterCard, and so on.
Let's skip the Address class and let's go back to your problem now.
So far we have identified and created properly all the value objects we need. Now we need to create an abstraction for representing an email, phonenumber, address as contact methods and if we keep loyal to the domain language we could say:
ContactMethod.for(Email.fromString("monica#gmail.com"));
or
ContactMethod.for(PhoneNumber("34234234234"));
etc
so our ContactMethod would look like:
class ContactMethod {
static EMAIL = 1;
static PHONE_TYPE = 2;
static ADDRESS_TYPE = 3;
String type;
String value;
ContactMethod(int aType, String aValue) {
type = aType;
value = aValue;
}
String getType()
String getValue()
public static ContactMethod at(Email anEmail) {
return new ContactMethod(EMAIL, anEmail.asString());
}
public static ContactMethod at(PhoneNumber aPhoneNumber) {
return new ContactMethod(PHONE_TYPE, aPhoneNumber.asString());
}
public static ContactMethod at(Address anAddress) {
return new ContactMethod(ADDRESS_TYPE, anAddress.asString());
}
}
See that ContactMethod is also an immutable class, actually a rule of thumb is that an Aggregate root should have ideally only an aggregation of value objects.
This is finally how your Person class would look like:
class Person {
List<ContactMethod> contactMethods;
contactedAt(Email anEmail) {
contactMethods.add(ContactMethod.at(anEmail));
}
contactedAt(PhoneNumber aPhoneNumber) {
contactMethods.add(ContactMethod.at(aPhoneNumber));
}
contactedAt(Address anAddress) {
contactMethods.add(ContactMethod.at(anAddress));
}
}
On my journey of learning DDD sometimes I see patterns instead of problems... an interesting example Everything seems to be an Aggregate Root is another answer I had provided regarding a menu, which had different categories such as starter, main, desert etc.
I had modeled this implicitly as a category string. After i posted there was a second answer where someone suggested modeling these as explicit lists of:
Menu {
List<Food> starters;
List<Food> entrees;
List<Food> desserts;
List<Food> drinks;
}
In this way, the entire concept of the category for a food was removed, this was enlightening for me and saw a different way of modeling and in this case reducing complexity.
My view is to try and model the code so that if I sat down with the business expert (who is not a developer) and showed them the use case code from a high level person.SetMobileNumber("078321411", Countries.UK) they would be able to understand it:
public void HandleUpdateMobileCommand(UpdateMobileNumber command)
{
// repositories, services etc are provided in this handler class constructor
var user = this.UserRepository.GetById(command.UserId);
user.SetMobile(command.number, command.country);
this.UserRepository.Save(user);
// send an SMS, this would get the number from user.Mobile
this.SmsService.SendThankYouMessage(user);
}
Or even better, you could have a MobileUpdated event get fired when you update the user mobile, to which some code somewhere else (which is an expert on sending SMS messages, and nothing else) is listening to these events - for me this is the real power of DDD of breaking down code in to expert systems.
So in summary, I think your second suggestion of explicitly modeling with Post, Mobile, Landline and Email makes most sense.
I wouldn't say this a DDD domain or not as there isn't enough information on any complex logic (or multi-user race conditions) that you require, just to mention don't forget that you may be better writing a CRUD app if that makes more sense in this situation.
There's this central idea in DDD that domain modelling must take shape through discussion with domain experts. If you're making up these class names out of thin air, chances are they won't exactly match your real domain. Trivial ones such as Email or Telephone should be correct, but maybe for others you want feedback from an expert first.
Generally speaking, it's a good idea indeed to favor semantically rich modelling with dedicated value objects over primitive types. In C# it comes at a cost though since the amount of boilerplate code needed is huge (unlike F# for instance). This is why I usually prefer to do it only when the type has more than a single property or when there are specific construction rules or invariants to it.
One good thing you can do is model your types as immutable Value Objects. So something like:
public class Telephone
{
public string AreaCode { get; set; }
public string TelephoneNo { get; set; }
}
Might become:
public class TelephoneNumber
{
private string areaCode;
private string subscriberNumber;
private TelephoneNumber()
{
}
public TelephoneNumber(string areaCode, string subscriberNumber)
{
this.AreaCode = areaCode;
this.SubscriberNumber = subscriberNumber;
}
public string AreaCode
{
get
{
return this.areaCode;
}
private set
{
if (value == null)
{
throw new ArgumentNullException("AreaCode");
}
if ((value.Length <= 0) || (value.Length > 5))
{
throw new ArgumentOutOfRangeException("AreaCode");
}
this.areaCode = value;
}
}
// Etc.
}

Custom organized data accessing via classes and constructors

struggling To achieve a solution for a basic Task:
working with more than one Sql Data table, as a source, for a WebSite application...
that's what leads me here once again... seeking for an Experienced C# .net Developers Help.
i was just trying to add some basic logic for a proper implementation,Like using
a dedicated namespace & classes, To Hold reference for All DATABASE tables,
(before i try working / learning about Entities Framework approach.)
i would like to try implement same of basic features of EF ...by my self, and that way... i will also learn how to properly work with classes.
as it is so far ... structured : with my little knowledge
a 'helper'.. namespace , say the company name is: HT technologies
so I've named the namespace HT_DbSchema ...that contains :
tables names
public sealed class HTDB_Tables
{
public const string Customers= "Customers";
public const string Times= "Times";
}
tables IDs
public sealed class HT_tblIDs
{
public const int tblCustomersID = 1, tblTimesID = 2;
}
tables Columns Lists ...(just one example)
public class HTDB_Cols
{
public class tblCustomers
{
public const string CustId = "custId",
CustName = "custName",
CellPhone = "cellPhone" .... etc'
}
}
and as all those 3 classes are serving all projects ..
there's another helper class for constructor Per Table For the Current Project
public class DBMetaDetails
{
public struct DbTable
{
public string TableName { get; set; }
public int TableID { get; set; }
}
}
so still these are all construction / helpers Classes and are separated from the project,
now for current project
What is The Appropriate way to get it done, using above Classes and constructor within a project
(i could name those templates)
what i was doing so far to implement some order is :
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
.... some other App inits here
}
else
{
}
// this method should be the one that instanciates the DbTable struct
//and set the values of tables name and "ID"
setTablesReferences();
}
And Here's where the confusion starts :
in a day by day usage i want to try implement it in a WebSite application :
public void setTableReferences()
{
DBMetaDetails.DbTable CustMeta = new DBMetaDetails.DbTable();
DBMetaDetails.DbTable TimesMeta = new DBMetaDetails.DbTable();
}
so now i need to set CustMeta & TimesMeta details(ids & names)
the struct has a kind of a template structure a kind'a systematic technique to initialize and assign values, so it brings some decent order to my logic with it's existence .
so what is the confusing part ?
from one point of view(safety), i need those tables detailes to be readonly
so DbTable.TableID, and DbTable.TableName would not get overWriten by mistake.
having said that, there should be only one place it could be SET ... a dedicated section of the application, like setTableReferences() above,... there i might add :
CustMeta.TableID = HT_tblIDs.tblCustomersID
CustMeta.TableName = HTDB_Tables.Customers;
on the other hand, i need the information of the tables to be Accessible,
so if let's say i would like to add those DataTables into a DataSet
DataSet ALLTablesSet = new DataSet();
// assuming the SQL actions already been taken in another method previosly...
// so DataTable is already retrived from DB
//...but only as a short usage example:
AllTablesSet.Tables.Add(new DataTable(CustMeta.TableName));
My Question is What is the Correct Way to work with structs ... as in My Scenario,
So in one section of app: you would initialize - assign it with a value privately.
and from other sections of the app you could use its value (Only For Readings)
so that way, the application will not be able to access it's value for writing,
only by reading values, i think it should be trough another (Public ReadOnly) Variable.
so that variable was meant to be exposed ...and it's value could not be "harmed"
If I understand the question correctly, the way I would prevent other code from modifying it is by removing the setters on the properties. However, you still need to set them at some point, so rather than removing the setters completely, you can just make them private. For example:
public string TableName { get; private set; }
If you do this, the only place you can set this data is within the struct itself, so you would need to create a constructor that took the initial values you wanted. So something like:
public struct DbTable
{
public DbTable(string tableName, int tableId)
{
this.TableName = tableName;
this.TableID = tableId;
}
public string TableName { get; private set; }
public int TableID { get; private set; }
}

How can I make something like a dynamic enumeration in C#?

In an application I'm building I had an enumeration of account statuses:
public enum AccountStatus
{
Active = 1,
Trial = 2,
Canceled = 3
}
However, I needed more information from an AccountStatus so I made a class which has a few extra useful properties:
public class AccountStatus
{
public int Id {get; set;}
public string Description {get; set;}
public bool IsActive {get; set;}
public bool CanReactivate {get; set;}
}
This class get populated from a database table that might look like this:
1, "Active", True, True
2, "Trial", True, True
3, "ExpiredTrial", False, True
4, "Expelled", False, False
This is really handy when I have a customer object that uses the AccountStatus because I can write code like:
if(customer.Status.CanReactivate) // Show reactivation form
However, I have lost something equally important. I can no longer do this:
if(customer.Status == AccountStatus.Active) // allow some stuff to happen
What would be the best way, if its even possible, to include something that will allow me to mimic the enumeration within the class. I know that I could add public static fields to the AccountStatus class, but ultimately this doesn't work because if the database changes the code would have to be manually updated. By this, I mean:
public static readonly AccountStatus Active = new AccountStatus(1);
public static readonly AccountStatus Trial = new AccountStatus(2);
// etc, etc ...
I imagine there is probably a pattern for this somewhere, I just don't know what its called.
Any ideas?
CLARIFICATION
Based on the answers so far I need to clarify a couple of things.
The table above is a brief example. In my actual table there a many records, I have 12 in there right now. Plus we can add more or remove some existing. This is what I meant by "dynamic" in my question title.
Secondly, I gave a very simple use case for the ability I lost which apparently confused matters. Here is another real example:
if(customer.Status == AccountStatus.Trial || customer.Status == AccountStatus.ExpiredTrial)
... neither Trial nor ExpiredTrial are boolean values on the property. I don't want to add them either. That would set an even worse precedent than the one I'm trying to avoid (meaning I would have to add a new property to the class every time I added a new record to the table).
UPDATE
I selected an answer which didn't really meet was I was looking for, but suggests that I was looking for something unnecessary. After thinking about this, I concur. While adding an enum or static fields does duplicate some work (ie, having the values in both code and in a table) I think the benefits outweigh the negatives.
But why can't you use the enumeration as a property of that class..?
public enum State
{
Active = 1,
Trial = 2,
Canceled = 3
}
public class AccountStatus
{
public int Id {get; set;}
public State State {get; set;}
public string Description {get; set;}
public bool IsActive {get; set;}
public bool CanReactivate {get; set;}
}
And then:
if(customer.Status == AccountStatus.State.Active) // allow some stuff to happen
Rather than working with a strongly-typed enum, you could just do comparisons using a string:
public static readonly AccountStatus Active = new AccountStatus("Active");
or load the type from your database:
public static readonly AccountStatus Trial = new AccountStatus( reader["StatusField"] );
You can then do explicit comparisons:
if(customer.Status == "Active")
You lose the strong typing, but that's what dynamic means :-). You can store the known string values in constants to get some of this back.
edit
You could of course do this using the corresponding integer values, like you hinted at the end of your post. But strings are easier to read, and in this case using integers doesn't offer any sort of typing benefits.
I think you could achieve this by using a Flags enumeration where you can combine values:
[Flags]
public enum AccountStatus
{
Expelled = 1,
Active = 2,
CanReactivate = 4,
Canceled = 8,
Trial = Active | CanReactivate,
ExpiredTrial = CanReactivate,
}
However, it feels as if those different enum values move along different scales (some describe state, some describe valid actions), so it might not be the right solution. Perhaps you should instead split it into two enums.
I don't understand why you can't just write:
if (customer.Status.IsActive)
if you do/want something like this in your application:
if(customer.Status ==
AccountStatus.Active)
You have to know in your code that "Active" is a possible status. How else would you be able to write the actual word Active in your code. The status object can be dynamic, but the rest of the program that uses the status has to know what types of status exist in order to do something useful with it. What if active doesn't exist anymore, the status object may not need to be reimplemented, but the code that uses it does.
If every kind status is fully defined by parameters like it almost seems (active and trail have the same parameters, so more are needed to differentiate (expiration date?)), then check those parameters.
If a combination of parameters has to have a name, then make some kind of lookuptable where you can translate the name into its associated parameters, or its inverse. That way the name can be dynamic for that piece of code, and the parameter values are to upto some degree.
A possible real dynamic solution would be to implement some sort of scripting language/xml file/... that enables the user to specify the kinds of status, their parameters, and associate them with system behavior.
I still think your best bet is to add your missing cases to the class.
public class AccountStatus
{
public int Id {get; set;}
public string Description {get; set;}
public bool IsActive {get; set;}
public bool CanReactivate {get; set;}
public bool Trial {get; set;}
public bool ExpiredTrial {get; set;}
}
Which you can call in a simpler form than your example:
if(customer.AccountStatus.Trial || customer.AccountStatus.ExpiredTrial)
If you need to check a UserDefined status, expose that as a separate property:
public AccountStatusCode Status {get; set;}
...and call it like this:
if(customer.Status == AccountStatus.Active)
You can still add a constructor to it if you want to set an initial status.
You could make a many-to-many relationship between AccountStatus and Description. This way you can, at runtime, load all the different Descriptions you got, and then compare against those, using some sort of enumeration :)
This code does what you described in your post. I didn't code CanReactivate because you didn't say what the logic for that was.
public enum AccountStatusCode
{
Active = 1,
Trial = 2,
Canceled = 3
}
public class AccountStatus
{
private AccountStatusEnum status
//
// Constructor sets initial status.
public AccountStatus(int status)
{
this.Status = (AccountStatusCode)status;
}
public int Id { get; set; }
public string Description { get; set; }
//
//
public bool IsActive
{
get { return status == AccountStatusCode.Active; }
}
public bool CanReactivate { get; set; }
}
Note that, since you said you wanted to specify the initial account status as an int, I accept an int in the constructor, but then I cast it to an AccountStatusEnum for assigning it to the member variable. That's probably not the best practice...You should pass the constructor an AccountStatusCode value.
OK, well if you're working in C# 3.0, you could try extension methods:
// Define extension method like this:
public static bool IsActive(this AccountStatus status)
{
get { return status == AccountStatusCode.Active; }
}
//
// Call it like this:
if (AccountStatus.IsActive())
That keeps it out of your class.
I think what judo tried to explain is - a new status in the DB will require to put checking s for that new status in the conditional blocks. I think I am also doing something same. Only thing I am doing is I am also using another 'rank' field so that I can do range comparison instead of hard coding all the statuses.
For example instead of doing:
if(customer.Status == AccountStatus.Trial || customer.Status == AccountStatus.ExpiredTrial)
if I could put them in order I could do:
if(customer.Status < AccountStatus.Trial) as in our enum we can put them as ordered. So a new status in a new page wont break the other page's logics (depends on the rank of the status).

Categories

Resources