C#: Encapsulation of for example collections - c#

I am wondering which one of these would be considered the cleanest or best to use and why.
One of them exposes the a list of passengers, which let the user add and remove etc. The other hides the list and only let the user enumerate them and add using a special method.
Example 1
class Bus
{
public IEnumerable<Person> Passengers { get { return passengers; } }
private List<Passengers> passengers;
public Bus()
{
passengers = new List<Passenger>();
}
public void AddPassenger(Passenger passenger)
{
passengers.Add(passenger);
}
}
var bus = new Bus1();
bus.AddPassenger(new Passenger());
foreach(var passenger in bus.Passengers)
Console.WriteLine(passenger);
Example 2
class Bus
{
public List<Person> Passengers { get; private set; }
public Bus()
{
Passengers = new List<Passenger>();
}
}
var bus = new Bus();
bus.Passengers.Add(new Passenger());
foreach(var passenger in bus.Passengers)
Console.WriteLine(passenger);
The first class I would say is better encapsulated. And in this exact case, that might be the better approach (since you should probably make sure it's space left on the bus, etc.). But I guess there might be cases where the second class may be useful as well? Like if the class doesn't really care what happens to that list as long as it has one. What do you think?

In example one, it is possible to mutate your collection.
Consider the following:
var passengers = (List<Passenger>)bus.Passengers;
// Now I have control of the list!
passengers.Add(...);
passengers.Remove(...);
To fix this, you might consider something like this:
class Bus
{
private List<Passenger> passengers;
// Never expose the original collection
public IEnumerable<Passenger> Passengers
{
get { return passengers.Select(p => p); }
}
// Or expose the original collection as read only
public ReadOnlyCollection<Passenger> ReadOnlyPassengers
{
get { return passengers.AsReadOnly(); }
}
public void AddPassenger(Passenger passenger)
{
passengers.Add(passenger);
}
}

In most cases I would consider example 2 to be acceptable provided that the underlying type was extensible and/or exposed some form of onAdded/onRemoved events so that your internal class can respond to any changes to the collection.
In this case List<T> isn't suitable as there is no way for the class to know if something has been added. Instead you should use a Collection because the Collection<T> class has several virtual members (Insert,Remove,Set,Clear) that can be overridden and event triggers added to notify the wrapping class.
(You do also have to be aware that users of the class can modify the items in the list/collection without the parent class knowing about it, so make sure that you don't rely on the items being unchanged - unless they are immutable obviously - or you can provide onChanged style events if you need to.)

Run your respective examples through FxCop and that should give you a hint about the risks of exposing List<T>

I would say it all comes down to your situation. I would normally go for option 2 as it is the simplest, unless you have a business reason to add tighter controls to it.

Option 2 is the simplest, but that lets other classes to add/remove elements to the collection, which can be dangerous.
I think a good heuristic is to consider what the wrapper methods do. If your AddPassenger (or Remove, or others) method is simply relaying the call to the collection, then I would go for the simpler version. If you have to check the elements before inserting them, then option 1 is basically unavoidable. If you have to keep track of the elements inserted/deleted, you can go either way. With option 2 you have to register events on the collection to get notifications, and with option 1 you have to create wrappers for every operation on the list that you want to use (e.g. if you want Insert as well as Add), so I guess it depends.

Related

Should I use a set to prevent items being added more than once to the collection by mistake?

Please see the code below:
public class Customer
{
private readonly IHashSet<Order> _orders = new Set<Order>();
public string FirstName { get; set; }
public string LastName { get; set; }
public string Province { get; set; }
public IEnumerable<Order> Orders
{
get { foreach (var order in _orders) yield return order; }
}
internal void AddOrder(Order order)
{
_orders.Add(order);
}
}
I am trying to decide whether the _orders property should be a List (which I would normally use) or a Set. The only reason a duplicate order would be added is if the client code added a duplicate by mistake. Does that warrant the use of a Set? Is that a valid use case for a Set?
Sure, this is a valid use case, if duplicate orders are not allowed.
Since you expose IEnumerable<Order> instead of IList<Order> you don't seem to be interested in keeping the insertion order, or let the caller use it like a list or array. So a HashSet<T> is perfect here. The database is the best place to ensure that no duplicates are added, but it's not wrong to check that also at client-side. On this way you can handle bugs early and report them in your logs.
public class Customer
{
private readonly HashSet<Order> _orders = new HashSet<Order>();
public IEnumerable<Order> Orders => _orders;
// ...
internal void AddOrder(Order order)
{
_orders.Add(order);
}
}
Note that you should override Equals+GetHasCode in Order, implement IEquatable<Order> or pass a custom IEquatable<Comparer> to the HashSet constructor.
You have tagged your question with domain-driven-design tag, so the answer should be given in this context.
There is a rule in DDD called "make explicit what is implicit". If you don't want to have duplicates in your orders, in my opinion you should add some simple code that makes this rule explicit. It can be just a simple vetoIfOrderIsDupicated private method or something similar. It will give you a chance to communicate your team mates (or even you in the future) that there is a rule which should not be broken. If you just change this collection to Set, it doesn't carry any information WHY this is a Set. In the future someone from your team (or you personally) will refactor this code for example from performance perspective and will change Set to some high performance List, but will loose the rule.
So answering your question: I recommend to make the rule explicit. And collection can be Set if you want.
Additionally and not correlated to question, I don't know your domain, but it seems to me, that Order is another Aggregate Root. If yes, you shouldn't reference both Aggregate Roots. Instead you should reference IDs of AggR. So _orders should be collection of OrderID.

Seeking an elegant way for inherited classes to have a "StateName" property

See my solution below -- search for UPDATE.
I have an extensive state machine architecture, which I'm implementing by creating a class for each state (there are multiple machines, but the states for all inherit from the same 'MachineState' class). Each state has a static property "StateName":
public class SomeState: MachineState
{
// THIS BLOCK SHOULD BE COPIED TO ALL STATE CLASSES!!
private static string _StateName;
public static string StateName
{
get {
if (_StateName == null)
{
_StateName = MethodBase
.GetCurrentMethod()
.DeclaringType
.ToString()
.Split(new char[] { '.' })
.ToList()
.Last();
}
return _StateName;
}
}
// END OF BLOCK
public SomeState(Queue<string> messages) //
: base(messages)
{
...
}
...
}
Ugh.
At least I'll call the processor-intensive stuff to get the name only once per class -- for my purposes, that's an acceptable cost. But I would really like to find some way for them to "inherit" this code -- or at least some way for them to include it something like a macro. I have an abstract property, so if it's not implemented I'll catch it at compile time; but still, there's got to be a way to avoid copying that mess into EVERY class -- and then having to CHANGE it in every class if the need ever arises.
Any ideas?
Thanks.
------------ UPDATE ---------------------------------------
Life is full of compromises; this one I can live with. #Tallek suggested this in the base class:
public static string GetStateName<T>() where T : MachineState
{
return typeof(T).Name;
}
I integrated that with my static property, like this (for class 'SomeState'):
// THIS BLOCK SHOULD BE COPIED TO ALL STATE CLASSES!!
public static string StateName { get { return GetStateName<SomeState>(); } }
It isn't perfect; I'll have to be sure to get the correct state name in the GetStateName call for each class. But it does two things I was anxious to do: it moves the logic into a single location, and it is easier to read. Keeping StateName abstract will help me catch any state that hasn't implemented StateName.
Thanks again, to all.
You have a state
Your states are classes
You want to compare that state to another
You don't want to instanciate states in order to compare
I don't see you doing it easier than:
if(state.GetType() == typeof(SomeState))
I potentially agree with CodeCaster. 20 or 30 states is not that large for an enum.
Based on your description of receiving a message and identifying the handler for that message, combined with looking at your example:
if(stateName == SomeState.StateName) { }
This implies you have stateName as a parameter. So you have an if block for every state so you can identify which one the message applies to?
if(stateName == SomeState.StateName) {
}
if(stateName == OtherState.StateName) {
}
If that is the case...
(big if given limited use case information, the rest of this answer is based on that premise so don't flame me if the rest of this doesn't apply)
You desire to have all classes automatically have this StateName property. This seems DRY, but then we see you still have to have an if block for each state, which is less DRY since there's more code to that IMO. You've traded a DRY for another DRY.
I would have enums which each have a
public enum States {
...
[Handler(typeof(SomeState))]
SomeState = 5,
...
Combined with a factory pattern, and now you throw out all the if blocks and only need a call to your factory:
MachineState newState = StateFactory.Create(stateName);
The factory uses Enum.Parse to convert the stateName into an enum, from which you access the attribute to get the type you need to instantiate. No switch/case/if/else needed.
This means every time you implement a new state class, you only need to touch one place, and that is the enum, and that has minimal code repetition.
If each if block has specific logic in it for that particular State
Move that code into a HandleMessage method defined in a MachineState or IMachineState interface, which has an implementation for each SomeState to do the stuff specific for that state. Let's assume your message indicates the stateName and maybe there's some "content" or "data" in the message that needs to be processed:
MachineState newState = StateFactory.Create(stateName);
newState.HandleMessage(messageContent);
I realize it's probably more complicated than that. You might need to seperate state from state handling into separate classes to make this work well. It's hard say. I would certainly mull this over pretty heavily though if I were in your shoes.
Its not great, but maybe worth considering...
public class MachineState
{
public static string GetStateName<T>() where T : MachineState
{
return typeof(T).Name;
}
}
Use like this:
if("MyState" == MachineState.GetStateName<MyState>()) { ... }
You could accomplish this with an extension method:
public static string GetStateName(this MachineState state) {
return state.GetType().Name;
}
Use it like this:
if(state.GetStateName() == "SomeState") { /* Do something */ }
Bake in your own caching if you want: you have access to any static structures you want here.

passing an instance into a method in c#

so ive been doing this assignment all night now and I think ive gone completely wrong on one part. this is the section im stuck on:
TableOrder class will carry two methods for adding items from the menu:
AddFood(), AddDrink(). Each method will pass in a prepared instance of
either the FoodItem or DrinkItem class you previously created. It is expected that the order system will maintain a separate collection
of drinks from food given that we will be passing the drinks orders to
bar staff and likewise food orders to the kitchen.
I have previously created two classes to for FoodItem and DrinkItem but am struggling to grasp the concept of what the question is asking. Please help!
hopefully somebody can explain what it is i am doin wrong. this is the code i have so far...
List<DrinkItem> DrinkMenu = new List<DrinkItem>();
public DrinkItem AddDrink(DrinkItem drinkItem)
{
return drinkItem;
}
public List<DrinkItem> OrderedDrink
{
get
{
return DrinkMenu;
}
}
the next section is as follows:
The TableOrder class provides two separate properties given below, each of which returns a copy of the stored items. Each are expected to return an instance of the List class where T is the appropriate class. It is not expected that I can set these food and drink using these properties.
a. OrderedFood
b. OrderedDrink.
i have ammended the first section and it works, but it has now given me errors on my 2nd part... any ideas as to why this might have happened?
I am going to try to give you some ideas.
First of all you need to have a TableOrder class
public class TableOrder
{
}
Responsibility of the class is: class will carry two methods for adding items from the menu
So, you create two methods in the class who will add things to the order list:
public void AddFood()
{
}
public void AddDrink()
{
}
You also need order list and according to the requirement you need two order lists one for food and another for drink. So, you put two fields in the class like,
private List<FoodItem> FoodOrders = new List<FoodItem>();
private List<DrinkItem> DrinkOrders = new List<DrinkItem>();
In the method you just pass items and add them to this list
public void AddFood(FoodItem fo)
{
FoodOrders.Add(fo);
}
public void AddDrink(DrinkItem do)
{
DrinkOrders.Add(do);
}
And while you are using TableOrder you just need to call these methods to add orders like,
tableOrder.AddDrink(drinkItem);
As i understand this the AddDrink Method should add the Drink to the OrderedDrink List eachtime a Drink is ordered:
public DrinkItem AddDrink(DrinkItem drinkItem)
{
OrderedDrink.Add(drinkItem);
return drinkItem;
}
And if the return value is not needed you may consider declaring the Method as void.
Important would also be to empty the OrderedDrink List eachtime its passed to the kitchen.
The question is asking you to write a class TableOrder which contains two collections. One for storing the ordered DrinkItemss and one for storing the ordered FoodItems. This class should provide two methods:
AddDrink which gets passed a DrinkItem and adds it to the other drinks stored in your collection
AddFood which gets passed a FoodItem and adds it to the collection of ordered foods
In general a method which only returns its parameter without doing anything else like you have written for AddDrink is completely useless so this is an quick and easy check if what you wrote can be right.

Pros/Cons on Lists with subsidiary objects

I'm again in the position to figure a way out to handle lists with subsidiary objects on our business objects.
Actually, our code often looks like this:
public class Object
{
private List<SubsidiaryObject> subsidiaryObjects = null;
public List<SubsidiaryObject> SubsidiaryObjects
{
get
{
if (this.subsidiaryObjects == null)
{
this.subsidiaryObjects = DBClass.LoadListFromDatabase();
}
return this.subsidiaryObjects;
}
set
{
this.subsidiaryObjects = value;
}
}
}
The Con on this:
The property is referenced in presentation layer and used for DataBinding. Releasing the reference to the actual list and replacing it with a new one will end in an referenced list in the GUI that does not have anything left with the list on the object.
The Pro on this:
Easy way of reloading the list (just set the reference to null and then get it again).
I developed another class that uses the following pattern:
public class Object2
{
private readonly List<SubsidiaryObject> subsidiaryObjects = new List<SubsidiaryObject>();
public List<SubsidiaryObject> SubsidiaryObjects
{
get
{
return this.subsidiaryObjects;
}
}
public void ReloadSubsidiaryObjects()
{
this.SubsidiaryObjects.Clear();
this.SubsidiaryObjects.AddRange(DBClass.LoadListFromDatabase());
}
}
Pro on this:
Reference is continous.
The Con on this:
Reloading the list is more difficult, since it just cannot be replaced, but must be cleared/filled with reloaded items.
What is your preferred way, for what situations?
What do you see as Pro/Con for either of these to patterns?
Since this is only a general question, not for a specific problem, every answer is welcome.
Do you need the caller to be able to modify the list? If not you should consider returning IEnumerable<T> or ReadOnlyCollection instead. And even if you do, you will probably be better off making cover versions for Add/Remove so you can intercept modifications. Handing a reference to internal state is not a good idea IMO.
A third option would be to go with option 2, but to create a new instance of the Object2 type each time you need to repopulate the list. Without additional context for the question, that is the option I would select, but there may be reasons why you would want to hold on to the original instance.

Exposing array-like data structure using properties

Its typical to expose internal data structures as properties to your business class. But when we have to expose array-like structures (like List<Rule> rules) we might encounter a problem of wrong usage (as in Option 1).
Its suggested to expose clone of such data structures as properties, so that internal structure does not get disturbed.
Does any one have a well-settled solution for this?
public class Rule
{
}
public class RulesManager
{
List<Rule> rules = new List<Rule>();
public List<Rule> Rules
{
get { return rules; }
set { rules = value; }
}
public void Add(Rule r)
{
rules.Add(r);
// Do something else after add;
}
public void Delete(Rule r)
{
rules.Remove(r);
// Do something else after delete;
}
}
public class CallingCode
{
public static void Main()
{
RulesManager r = new RulesManager();
// Option 1
r.Rules.Add(new Rule());
// Option 2
r.Add(new Rule());
}
}
Instead of returning a Clone, you can return a read-only version of rules using rules.AsReadOnly().
public IList<Rule> Rules
{
get { return rules.AsReadOnly(); }
// set { rules = value; -- should not be allowed to set if read only!
}
Note the IList.
Instead of returning a List you can return an IEnumerable. The IEnumerable allows the user to iterate through the collection, but it doesn't allow the user to modify it easily.
Alternatively you could return an arryay instead of a list. This will create a copy of the list that the user cannot easily modify.
Finally you should be aware that the user might also modify the contents of the collection. This may be what you want, but you might also want to return copies of your items.
I think it is quite common to expose the IList as a property, but I prefer to expose only explicit Add/Delete functions. You can also consider to implement one of the collection interfaces in your class (IList for instance), if you are developing something more of a framework.
Instead of:
public List<Rule> Rules
{
get { return rules; }
set { rules = value; }
}
I prefer to implement IEnumerable<T> and an indexer on the class, so that I have control over what happens to the list.
Check out the ReadOnlyCollection and the AsReadOnly() List method.
A basic workaround is to use List<T>.AsReadOnly() method, which will wrap the list around a ReadOnlyCollection to block any "write" access. Of course, you'd have to make the setter private, otherwise it would not make sense...
Another alternative would be to implement your own IList that would alert you in case of "write" access and allow you to perform your business logic.

Categories