I'm trying to recreate the generic List collection. This is my code to Add items to the collection and Show all of them:
public class Collect<TItem>
{
public Collect<TItem> collectObject;
public TItem firstObject;
public void Add(TItem item)
{
if (collectObject == null)
{
collectObject = new Collect<TItem>();
collectObject.firstObject = item;
}
else
{
this.collectObject.Add(item);
}
}
public void Show()
{
if (firstObject != null)
Console.WriteLine(firstObject.ToString());
if (collectObject != null)
collectObject.Show();
}
You'd use this class like this:
Collect<int> test = new Collect<int>();
test.Add(2);
test.Add(10);
test.Add(30);
test.Add(3);
test.Show();
It prints all of the values above, but the first item is always 0.
0
2
10
30
3
This is because the very first firstObject variable is never assigned and gets the default value, but I can't figure out a way to get this fixed. The book I learned this assigns the first firstObject variable in a constructor that expects a TItem object, but I want to do it without using a constructor for this collection (to recreate a List)
I know this is exactly the same like how a generic List works, but I just want to understand the logic behind it. Thanks for the help.
You can make your TItem nullable, which allows your test to work. Also, you need to set the firstObject in the top instance of Collect, not the referenced one.
public class Collect<TItem> where TItem : struct
{
public Collect<TItem> collectObject;
public TItem? firstObject;
public void Add(TItem item)
{
if (collectObject == null)
{
collectObject = new Collect<TItem>();
firstObject = item;
}
else
{
this.collectObject.Add(item);
}
}
public void Show()
{
if (firstObject.HasValue)
Console.WriteLine(firstObject.ToString());
if (collectObject != null)
collectObject.Show();
}
}
OK, this is doing my head in, but I think you want to do something like:
if (collectObject == null)
{
collectObject = new Collect<TItem>();
this.firstObject = item;
}
because otherwise you are never actually assigning anythign tothe firstobject property of the object you are creating.
What you doing wrong is collectObject.firstObject = item; should be this.firstObject = item;
I think you just have to change the line:
collectObject.firstObject = item;
to
firstObject = item;
This way your custom collection will always be represented by a "head" and a "tail" - I assume this is what you are tryin' to acomplish.
In other words when adding an item, you say "If this is the first time to add, then this is my 'head' of the list, else - insert it into the 'tail' of the list". Printing is with the same idea - print the "head" and then call the tail's print method (in your code 'Show' method).
First, this is certainly not how System.Collections.Generic.List<T> works. It uses an array internally, not a singly-linked list as you do. LinkedList<T> is somewhat similar to your collection, except it uses a doubly liked list.
Now, onto your issue. The problem with your collection is that it is not able to represent an empty value and it seems you want that. What I would suggest is to create another public class that represents the whole collection and change your Collect<T> only to an internal implementation (let's call it Node<T>). This way, the new collection class can contain null reference to Node<T>, when it is first constructed, which signifies an empty collection.
If this were production code, I'm pretty sure you would actually need to do something like this, because you are going to want to keep some information on a per-collection basis (like count).
Another option (which is usually taken by lists in functional languages) is to create an inheritance hierarchy similar to the following:
abstract class Node<T>
{ }
class FullNode<T> : Node<T>
{
public T Item { get; private set; }
public Node<T> Next { get; private set }
// constructor and possibly other members
}
class EmptyNode<T> : Node<T>
{ }
This way, you have separate types to represent a full node and an empty node. In those lists, it is usual to add new items to the front, not to the back, though.
I would suggest at least one other improvement, regarding the speed of adding, but I suppose your book will get to that.
Also, I'm quite sure this is the case, but I really hope you're not planning on using this code in any kind of production environment and that it is just an learning exercise.
Just to add a little bit more information...
The reason the 0 is being written out is because you have a != null check on the firstObject. Obviously, the default value of an integer is not null, it is zero, so when firstObject hasn't been set it will be zero and not null. I guess if you want to exclude any value that is not the default for that type you could change your check to:
if (firstObject != default(TItem))
That's probably not exactly what you want though as I'm sure zero could be a valid value in this instance.
Try a nullable type
Collect<int?> test = new Collect<int?>();
Related
I want to create an array of Disc which id like to include fields string[] Record, int NumberHeads and string extension. so basically grouping them and instantiate the array once and only once as i dont want more than one of this array in the memory. How can i do this as my fields dont seem to be under the array Disc and if i make them public and run the application i get a null reference exception.
I was initially using a struct but I came to realise these cannot be passed from class to class in C#.
class DiscType
{
private static DiscType[] disc;
private static string[];
public bool discSelect;
public int maxRecord;
public int numberHeads;
public string extension;
public static string[] Record
{
get
{
if (record == null)
{
record = new string[1000];
}
return record;
}
}
public static DiscType[] Disc
{
get
{
if (disc == null)
{
disc = new DiscType[10];
}
return disc;
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < DiscType.Disc.Length; i++)
{
DiscType.Disc[i].Record[i]= "1";
}
}
}
If you want only once instanciation of your array do it like that :
public class Singleton
{
private static Singleton instance;
public string[] MyArray { get; set; }
//better using a List<string>
private Singleton() {
//instanciate MyArray here
}
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
After that you just need to call it like that :
Singleton.intance.MyArray
You describe two problems:
After you think you created a DiscType and an array of records, your array of records only contains null values
Your DiscType is not a singleton.
Is Disctype a singleton?
Someone else already described how to create a Singleton, So I wont write this. However I doubt whether DiscType in your design really is a singleton. If you'd describe your design in words, would you talk about the one and only disctype, or would you say: "Although in my designed world it could be that there were several different disctypes, however because of the huge amount of memory and mabye because of the time it takes to create one, it is advised to use only one disctype during the session".
In the latter case, you should not design it as a singleton. The famous gang of four wrote in their book about design patterns (where the singleton is described) as one of the major rules of design:
Design for change
That means, that you should not restrict your design merely for the case that in the current usage it is not needed. If in your current configuration you only need one disctype, just create only one. If in future versions you need two, you don't need to change your disctype.
So careful review your design: are we talking about "the one and only disctype"? or are we only restricting to one because we don't have enough memory?
Why is my array of records empty
To understand this, you need to know the difference between value types and reference types. Simple types and structs are value types. They exist as soon as you declare them. Instances of classes are always reference types: you need to call new ... to create them. If you don't do this, the value is null.
Myclass X;
string text;
int i;
System.Drawing.Point p; // a Point is a struct!
X and text both have a null value, the only thing you can do with them before you assign something to them is compare them with null
i and p already have a value. You can get them and call their methods.
Back to your problem
Your code:
public static string[] Record
{
get
{
if (record == null)
{
record = new string[1000];
}
return record;
}
}
You assign a newly created object to record. the object is an array of strings, which are reference types. You haven't assigned anything to each string, so each string in your array is still null, and you can't do anything with them until you assign something.
The array of strings however is initialized. You can use methods of the array. You can ask for the length of the array. You can also ask for item[3] in which you get the uninitialized (null) string.
List instead of Array
By the way, this method of initializing is a bit unusual. I guess you don't want to reserve memory for records as long as you don't use them. You would have accomplished that by using List.
My advise is to familiarize yourself with class List. It will make your life so much easier. Before long you'll feel the desire to know all collection classes :-)
Not sure I'm able to formulate this question in a way someone would simply understand, so lets have a cool marketing example:
public class Part
{
public MemberType member;
...
}
public class Product
{
public Part part1;
...
}
...
Product product = new Product();
I need to modify the public product's part1. So, the natural method is to write something like:
product.part1 = new Part();
Now, an algorithm (let's say a sort of search one) would go through the product object and identify the part1 as an interesting part and returns reference to it:
Part Search(Product product)
{
Part part = null;
...
part = product.part1;
...
return part;
}
...
interesting_part = Search(product);
We can alter the product object via the interesting_part like
interesting_part.member = whatever;
Now, the question: in c/c++ if the Product.part1 is pointer to Part and Search returns address of this pointer, we could replace the part1 just by assigning new value to this address. AFAIK this is not possible for c# reference:
interesting_part = new Part();
Just creates new object and copies its reference to the interresting_part, but without knowing the member parent (product object), we are not able to modify the (product.part1) reference, just its content. We would need second level of the reference.
Is there something like "ref reference" type which would accept reference addresses? In such hypothetical case the search would return ref Part and assigning to such value would replace the referenced object with the new one.
Thanks.
You could create a Reference class
class Reference<T>
{
private Func<T> m_Getter;
private Action<T> m_Setter;
public Reference(Func<T> getter, Action<T> setter)
{
m_Getter = getter;
m_Setter = setter;
}
public T Value
{
get{return m_Getter();}
set{m_Setter(value);}
}
}
Now you can say
Reference<Part> Search(Product product)
{
Part part = null;
...
part = product.part1;
var reference=new Reference<Part>(()=>product.part, (value)=>product.part1=value);
return refernce;
}
var partReference = Search(product);
partReference.Value = someNewPart;
In a very similar situation, I keep a reference of the parent in each child object. Simple and works.
public class Part
{
public MemberType member;
...
public Product parent;
Part(Product p)
{
parent = p;
}
}
public class Product
{
public Part part1;
...
}
I don't think you can do that. You would need to mutate a reference to you product object, or have some other added layer of reference.
So you need to build a Proxy object. The Product would get a reference to the Proxy and the (hidden) Part can be exchanged. This is a common OO design pattern. Of course the Proxy can delegate method calls to the Part.
If you want to change the field, you can do this,
class Program
{
static void Main(string[] args)
{
var holder = new Holder();
holder.CurrentPart = new Part() { Name = "Inital Part" };
Console.WriteLine(holder.CurrentPart.Name);
TestRef(ref holder.CurrentPart);
Console.WriteLine(holder.CurrentPart.Name);
Console.ReadKey();
}
public static void TestRef(ref Part part)
{
part = new Part() { Name = "changed" };
}
}
public class Part
{
public string Name;
}
public class Holder
{
public Part CurrentPart;
}
This won't work with property, indexers and so.
As far as I know, there isn't any way to alter an object's "parent" without having a reference to it. So I believe the official answer to your question as written is "no".
That said, there are many ways to accomplish the task as written. The easiest option is to add a reference to the parent from the part object. You end up with something like:
public class Part
{
public Product parentProduct;
public MemberType member;
...
}
Now whenever you have a part object you also know what product the part goes with (IF it does indeed go with a part at all). This is not necessarily a bad coding style but there certainly are pitfalls. You can update the product, but forget to update the parts in that product, you are coding so that parts have one product, but what if that part has many products? You can see how this works, but it can get complicated.
Taking this and making it more generic you can have reference the parent as an object type. That looks like:
public class Part
{
public object parent;
public MemberType member;
...
}
Now when you want to use the parent you can write something like:
var parentProduct = myPart.parent as Product;
This will convert the parent to a product or will assign null if the parent is not of the type Product. Now parts can have parents of any given type you would want and you have made the pattern more flexible.
One final pattern I know people use frequently is delegates. This allows you to pass in a function effectively modifying the way "search" is working. Say what you really want to do is search, then process the results in some manner, but you want that processing to be flexible (this may be what you were doing with the results). In that case, you can use delegates as follows:
// define the delegate
public delegate void ProcessResultDelegate(Product result, Part interestingPart);
// an example search function
public static void RunSearch(IEnumerable<Product> products, ProcessResultDelegate processingHelper)
{
// run the search... then call the processing function
processingHelper(searchResult, interestingPart);
}
This pattern is more useful when you want to modify the behavior of a routine rather than the return value from that routine.
Anyways, hope these patterns help some!
I am almost embarrassed to ask this question, but as a long time C programmer I feel that perhaps I am not aware of the best way to do this in C#.
I have a member function that I need to return two lists of a custom type (List<MyType>) and I know beforehand that I will always have a return value of only two of these lists.
The obvious options are :
public List<List<MyType>> ReturnTwoLists();
or
public void ReturnTwoLists(ref List<MyType> listOne, ref List<myType> listTwo);
Both seem to be non-optimal.
Any suggestions on how to improve this?
The first way doesn't make it clear in the syntax that only 2 lists are being returned, and the second uses references rather then a return value, which seem so non-c#.
First of all, that should probably be out, not ref.
Second, you can declare and return a type containing the two lists.
Third, you can declare a generic Tuple and return an instance of that:
class Tuple<T,U> {
public Tuple(T first, U second) {
First = first;
Second = second;
}
public T First { get; private set; }
public U Second { get; private set; }
}
static class Tuple {
// The following method is declared to take advantage of
// compiler type inference features and let us not specify
// the type parameters manually.
public static Tuple<T,U> Create<T,U>(T first, U second) {
return new Tuple<T,U>(first, second);
}
}
return Tuple.Create(firstList, secondList);
You can extend this idea for different number of items.
Return this:
public class MyTwoLists {
public List<MyType> ListOne {get;set;}
public List<MyType> ListTwo {get;set;}
}
Your first suggestion isn't two lists. It's a list of lists.
The second option would do what you intend, but you might want to change it to use the out keyword instead of ref so the callers of your method will know the intention of what you're doing.
public void ReturnTwoLists(out List<MyType> listOne, out List<myType> listTwo);
You have a few options:
use a Pair if the lists are meaningless in order:
public Pair<List<MyType>,List<MyType> ReturnTwoLists()
{
return new Pair(new List<MyType(), new List<MyType());
}
You can use out or ref parameters, as you mentioned. This is a good option if one list is more meaningful than the other.
You could use a dictionary if the client will know the keys, or wants to do the work to look them up:
public Dictionary<string,List<MyType> ReturnTwoLists()
{
Dictionary<string,List<MyTpe>> d = new Dictionary<string,List<MyType>>();
d.Add("FirstList",new List<MyType>());
d.Add("SecondList",new List<MyType>());
return new Dictionary()(new List<MyType(), new List<MyType());
}
Or, the most "correct" solution in my eyes, for completeness and consistency, would be to create a simple data container class to hold the two lists. This provides a consumer with strongly-typed, good statically compiled (read: intellisense-enabled) return values to work with. The class can be nested right next to the method.
Create a simple Structure that holds both and return that as the output of the function?
Hi I'm trying to get some practice with Linked Lists.
I Defined an Object class called Student:
public class Student
{
protected string Student_Name;
protected int Student_ID;
protected int Student_Mark;
protected char Student_Grade;
public Student() // default Constructor
{
Student_Name = " ";
Student_ID = 0;
Student_Mark = 0;
Student_Grade = ' ';
}
public Student(string Sname, int Sid, int Smark, char Sgrade) // Constructor
{
int len = sname.Length;
Student_Name = sname.Substring(0, len);
//Student_Name = sname.Substring(0, sname.Length);
Student_ID = Sid;
Student_Mark = Smark;
Student_Grade = Sgrade;
}
}
and then a Node class:
public class S_Node
{
public Student Element;
public S_Node Link;
public S_Node()
{
Element = new Student();
Link = null;
}
public Node(Student theElement)
{
Element = theElement;
Link = null;
}
}
and the LinkedList:
public class S_LinkedList
{
protected S_Node header;
protected S_Node tail;
public S_LinkedList()
{
header = new S_Node();
Tail = new S_Node();
header.Link = Tail;
}
// METHODS which i don't know how to do it (never use linkedlist before)
}
I need to organize this data using a “linkedlist data structure type”.
Contain all methods of linkedlist as Adding nodes to the list as I've learned -->(Insert),Deleting nodes from the list,as I've learned -->((Remove),Traversing the lists I've learned -->((PrintList),Finding a node in the list as I've learned -->((Find , FindPrevious) the problem I'm selflearning and I've tried to search the net and read more from the stupid C# that was a disaster.
I've done too much that I'm so sad that i don't know how to complete it .
I'm trying hard to Use this classes to write an executable program and to Test it .
If you don't want to help in completing this program (hope not) at least show me some real examples or ideas , after all I'm a selflearner geek :-)
the head of the list.
( item1
Element: student1
Next ------------> ( item2
) Element: student2
Next ------------> ( item3
) Element: student3
Next: null
)
the tail of the list.
First of all, for you to be able to write the StudentList class, you need to write the client code first. Client code is the code that uses your student list. Also, don't just write one thing at a time and throw it away. Instead write a whole bunch of [test] cases that exercise the different ways you need to interact with the StudentList. Write exceptional cases too. But don't be tempted to write a swiss-army knife of a class that does everything just because it can. Write the minimal amount of code that gets the job done.
How you need to use the class will heavily dictate how the class is constructed. This is the essence of TDD or Test Driven Design.
Your biggest problem that I can see is you have no idea how you want to use the class. So lets do that first.
// create a list of students and print them back out.
StudentList list = new StudentList();
list.Add( new Student("Bob", 1234, 2, 'A') );
list.Add( new Student("Mary", 2345, 4, 'C') );
foreach( Student student in list)
{
Console.WriteLine(student.Name);
}
I add the students to the list, and then I print them out.
I have no need for my client code to see inside the StudentList. Therefore StudentList hides how it implements the linked list. Let's write the basics of the StudentList.
public class StudentList
{
private ListNode _firstElement; // always need to keep track of the head.
private class ListNode
{
public Student Element { get; set; }
public ListNode Next { get; set; }
}
public void Add(Student student) { /* TODO */ }
}
StudentList is pretty basic. Internally it keeps track of the first or head nodes. Keeping track of the first node is obviously always required.
You also might wonder why ListNode is declared inside of StudentList. What happens is the ListNode class is only accessible to the StudentList class. This is done because StudentList doesn't want to give out the details to it's internal implementation because it is controlling all access to the list. StudentList never reveals how the list is implemented. Implementation hiding is an important OO concept.
If we did allow client code to directly manipulate the list, there'd be no point having StudentList is the first place.
Let's go ahead and implement the Add() operation.
public void Add(Student student)
{
if (student == null)
throw new ArgumentNullException("student");
// create the new element
ListNode insert = new ListNode() { Element = student };
if( _firstElement == null )
{
_firstElement = insert;
return;
}
ListNode current = _firstElement;
while (current.Next != null)
{
current = current.Next;
}
current.Next = insert;
}
The Add operation has to find the last item in the list and then puts the new ListNode at the end. Not terribly efficient though. It's currently O(N) and Adding will get slower as the list gets longer.
Lets optimize this a little for inserts and rewrite the Add method. To make Add faster all we need to do is have StudentList keep track of the last element in the list.
private ListNode _lastElement; // keep track of the last element: Adding is O(1) instead of O(n)
public void Add(Student student)
{
if( student == null )
throw new ArgumentNullException("student");
// create the new element
ListNode insert = new ListNode() { Element = student };
if (_firstElement == null)
{
_firstElement = insert;
_lastElement = insert;
return;
}
// fix up Next reference
ListNode last = _lastElement;
last.Next = insert;
_lastElement = insert;
}
Now, when we add, we don't iterate. We just need to keep track of the head and tail references.
Next up: the foreach loop. StudentList is a collection, and being a collection we want to enumerate over it and use C#'s foreach. The C# compiler can't iterate magically. In order to use the foreach loop We need to provide the compiler with an enumerator to use even if the code we write doesn't explicitly appear to use the enumerator.
First though, lets re-visit how we iterate over a linked list.
// don't add this to StudentList
void IterateOverList( ListNode current )
{
while (current != null)
{
current = current.Next;
}
}
Okay. so let's hook into C#'s foreach loop and return an enumerator. To do that we alter StudentList to implement IEnumerable. This is getting a little bit advanced, but you should be able to figure out what's going on.
// StudentList now implements IEnumerable<Student>
public class StudentList : IEnumerable<Student>
{
// previous code omitted
#region IEnumerable<Student> Members
public IEnumerator<Student> GetEnumerator()
{
ListNode current = _firstElement;
while (current != null)
{
yield return current.Element;
current = current.Next;
}
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
You should be able to spot the linked list iteration in there. Don't get thrown by the yield keyword. All yield is doing is returning the current student back to the foreach loop. The enumarator stops returning students when it gets to the end of the linked list.
And that's it! The code works the way we want it to.
* This is by no means the only way to implement the list. I've opted to put the list logic in the StudentList and keep ListNode very basic. But the code does only what my very first unit test needs and nothing more. There are more optimizations you could make, and there are other ways of constructing the list.
Going forward: What you need to do is first create [unit] tests for what your code needs to do, then add the implementation you require.
* fyi I also rewrote the Student class. Bad naming and strange casing from a C# persepctive, not to mention the code you provided doesn't compile. I prefer the _ as a leader to private member variables. Some people don't like that, however you're new to this so I'll leave them in because they're easy to spot.
public class Student
{
private string _name;
private int _id;
private int _mark;
private char _letterGrade;
private Student() // hide default Constructor
{ }
public Student(string name, int id, int mark, char letterGrade) // Constructor
{
if( string.IsNullOrEmpty(name) )
throw new ArgumentNullException("name");
if( id <= 0 )
throw new ArgumentOutOfRangeException("id");
_name = name;
_id = id;
_mark = mark;
_letterGrade = letterGrade;
}
// read-only properties - compressed to 1 line for SO answer.
public string Name { get { return _name; } }
public int Id { get { return _id; } }
public int Mark { get { return _mark; } }
public char LetterGrade { get { return _letterGrade; } }
}
check parameters
pay attention to the different casing of properties, classes, and variables.
hide the default constructor. Why do I want to create students without real data?
provide some read-only properties.
This class is immutable as written (i.e. once you create a student, you can't change it).
I'll do one for you! You need to draw diagrams with each node as a box, and work out what code you need to use to change the list for each operation. See this for some inspiration:
http://en.wikipedia.org/wiki/Linked_list
The diagrams there don't show the main list class as a box, which you should have, with two arrows coming out of it for the header and tail.
Draw yourself some diagrams for the two cases in the Insert method to work out what's going on. One diagram for when there's nothing in the list and header is null, and another diagram for when there's something already in the list. Then from there work out the other operations.
public class S_LinkedList {
protected S_Node header = null;
protected S_Node tail = null;
public S_LinkedList()
{
}
// METHODS which i don't know how to do it (never use linkedlist before)
void Insert(Student s)
{
if( header == null )
{
header = new S_Node(s);
tail = header;
}
else
{
tail.Link = new S_Node(s);
tail = tail.Link;
}
}
}
The operations you are missing are:
Add:
set the link of the tail node to be the added node and set the tail to be the new node.
Remove/Delete:
is a bit tricky if you don't have a doubly linked list but with a singly linked list go throught he list from the head till you find the node you require keeping the previous node in a separate variable. When you find the node you are removing set the Link of the previous node to that nodes link. An optimization might be to check that it's not the link you are looking for.
Alternatively make it a doubly linked list and you don't need to keep track of the previous node.
Find:
Traverse the list from node to node till you find the one you are looking for.
read this wikipedia article for more info.
Look at this...
Although if you really want to learn how to do this you should write it in c or c++ at least then you'd be doing something useful...
Actually I don't see a reason to write your own linked list in C# (other then learning how it works) since the .NET already contains LinkedList generic class.
The concept of linked lists is not very difficult to understand. Implementation on the other hand ... can get a bit tricky.
I can also understand your frustration of trying to find information on the web about it. I have been in your boat before and everything varies from site to site. You really might want to invest in a data structures book as you I think the information you find will be much more clear and helpful than most information you find in the wild.
Implementing a linked list in Java/C# will be much easier if you have never used ll's before. However, once you get a better feel for it you will get a much better understanding for the ll's by creating them in C/C++.
From your code above, you will be better off thinking of each S_Node as just regular node that contains a Student object instead of thinking of it as a Student node (hope that makes sense). Same rules apply for your S_LinkedList class. A linked list is a list mode up of nodes. These nodes contain Student objects.
Hope this helps.
Try this as your Student class.
public class Student
{
protected string Name;
protected int ID;
protected int Mark;
protected char Grade;
public Student() // default Constructor
{
Name = "";
ID = 0;
Mark = 0;
Grade = '';
}
public Student(string Name, int ID, int Mark, char Grade) // Constructor
{
this.Name = Name;
this.ID = ID;
this.Mark = Mark;
this.Grade = Grade;
}
}
Your question, as I read it, is too vague. I would start by googling 'linked lists' or picking up a book on 'data structures'. When you run into a specific problem, ask it on here, and I'm sure someone will help you.
So I got into a friendly argument with a co-worker over a piece of code:
public sealed class NewObject
{
private string _stuff = string.Empty;
public string Stuff
{
get { return GetAllStuff(); }
}
private string GetAllStuff()
{
//Heavy string manipulation of _stuff
}
public NewObject(string stuffToStartWith)
{
_stuff = stuffToStartWith;
}
public static NewObject operator +(NewObject obj1, NewObject obj2)
{
if (obj1 == null)
throw new ArgumentNullException();
if (obj2 == null)
throw new ArgumentNullException();
NewObject result = new NewObject(string.Empty);
result._stuff = String.Concat(obj1._stuff, obj2._stuff);
return result;
}
}
The argument was over the operator override. My co-worker feels that it's not best programming practice to set values of private fields anywhere but the constructor. The solution proposed by my co-worker was to refactor the name of the Stuff property to AllStuff and add a property, Stuff, that has a get AND set accessor and use the new Stuff property in the operator override. Making it look like this:
public static NewObject operator +(NewObject obj1, NewObject obj2)
{
if (obj1 == null)
throw new ArgumentNullException();
if (obj2 == null)
throw new ArgumentNullException();
NewObject result = new NewObject(string.Empty);
result.Stuff = String.Concat(obj1.Stuff, obj2.Stuff);
return result;
}
I disagree. I feel the first way is better since it keeps the property read-only outside the class. My question is, which way is the best practice for object-oriented design?
You could give yourself a private set on the property (which would retain visibility or lack thereof while allowing you to use property syntax), but that doesn't really address the point.
Within the class, I say that variables are fair game. Anywhere outside, including inherited classes, should get and set the property, but within the declaring class I say it's OK to assign the private member.
The general issue has to do with a contract policy.
The notion of a (public set) property is that when it is called, other actions may be taken in addition to the semantic notion of changing state. For example, calling a setter may fire events, trigger a peripheral device and so on.
Your coworker is saying that by not using the property, you're side-stepping the contract and no events will be fired.
So here's you should do from your coworker's point of view:
this.Prop = CalculateSomeValue();
if (this.Prop < kPropMin) {
this.Prop = kPropMin;
}
else if (this.Prop > kPropMax * 2) {
this.Prop = kPropMax * 2;
}
this.Prop = this.Prop / 2;
Now, this is a contrived case, but I've just hit a possible heavyweight property up to three times in the get and up to three times in the set, and one of those might be illegal (setting to kHighLimit / 2). I can work around this by using a local and calling the set precisely once at the end. I'd rather just mess with the field, though.
I think a better approach is to take it pragmatically: use the property inside your class if and only if you want to invoke all the side-effects of a set or a get, otherwise obey the spirit of the property instead.
-- clarification --
By obey the spirit of the property, let's say that my set property looks like this:
bool PropValueOutOfRange(int val) {
return val < kPropMin || val > kPropMax;
}
public int Prop {
set {
if (PropValueOutOfRange(value))
throw new ArgumentOutOfRangeException("value");
if (PropValueConflictsWithInternalState(value))
throw new ArgumentException("value");
_prop = value;
NotifyPeriperalOfPropChange(_prop);
FirePropChangedEvent(/* whatever args might be needed */);
}
}
In this I've factored out a lot of the grungy details, but that lets me reuse them. So now I feel confident in touching the private field _prop because I have the same infrastructure for making sure that I keep it in range and to notify the peripheral and fire the event.
This lets me write this code:
_prop = CalculateSomeValue();
if (_prop < kPropMin)
_prop = kPropMin;
else if (_prop > kPropMax * 2)
_prop = kPropMax;
_prop /= 2;
NotifyPeripheralOfPropChange();
FirePropChangedEvent();
I'm using the same tools as those used to build the property so I'm working within the spirit of the property. I maintain correct range (but don't throw - I know better, I'm the implementer), hit the peripheral and fire events, and I do it thoughtfully, readably, and efficiently - not indiscriminately.
You're right
err... to elaborate, your private variables are yours to do as you please. If someone does an operation on you that changes the value of the object, (especially something like +), theres nothing wrong with modifying the value outside of the constructor. Thats the whole point of them being private.
Unless you want it immutable...
Update
The more i think about it, the more I believe your co-worker is confusing 'private' variables with 'constant' ones - or perhaps merging the two concepts. There is no reason that private variables have to remain the same throughout the life of the object, which is what your friend seems to be implying. const is for unchanging, private is for the object only, they are two very distinct patterns.
Update2
Also, his design falls apart if suddenly your object has more than just a string - and the variables are intertwined (think of a string object, that has a char* and a len, and must be maintained together). The last thing you want is for the user to have to deal with internal variables of an object. Let the object be an object and maintain its own internal values and present a single entity to the user.
I don't see what the benefit of his approach would be.
I personaly prefer to have no fields at all, hence I use auto-implemented private properties instead of private fields and public-get private-set properties if want to have public read-only properties.
If I have to add code to the property, I still only use the field inside of the property accessors and use the getters and setters everywhere else including the constructor.
I have to use fields, too, if I need readonly fields, but C# 4.0 will introduce read-only properties.
Further I would have avoided the whole problem by using the following code.
public static NewObject operator +(NewObject obj1, NewObject obj2)
{
return new NewObject(String.Concat(obj1.Stuff, obj2.Stuff));
}
My prefered implementation would be something like this.
public sealed class NewObject
{
private String Stuff { get; set; }
// Use a method instead of a property because the operation is heavy.
public String GetAllStuff()
{
// Heavy string manipulation of this.Stuff.
return this.Stuff;
}
// Or lets use a property because this.GetAllStuff() is not to heavy.
public String AllStuff
{
get { return this.GetAllStuff(); }
}
public NewObject(String stuffToStartWith)
{
this.Stuff = stuffToStartWith;
}
public static NewObject operator +(NewObject obj1, NewObject obj2)
{
// Error handling goes here.
return new NewObject(String.Concat(obj1.Stuff, obj2.Stuff);
}
}