Monday, December 27, 2010

#03 - How CSharp design patterns and refactoring differ from other languages - LINQ

This post continuing the post "How CSharp design patterns and refactoring differ from other languages - Part 01" and is based on Martin Fowler's "Refactoring" book.

Now here comes the first major difference between Java and CSharp
The next refactoring step is to extract Customer.GetTotalCharge() out of the loop of the enumerated rentals.

Making it the naive way it will look as folows:
        public double GetTotalCharge()
{
double result = 0;
foreach (var rental in _rentals)
result += rental.GetCharge();

return result;
}
But it could look much more elegant this way:
        public double GetTotalCharge()
{
return _rentals.Sum((Rental r) => r.GetCharge());
}
The only non-intutive part was that you have to first add "using System.Linq;" statement.

I'm not getting into how to work with LINQ, Anonymous methods and Lambbda Expressions, the same way I'm not getting into "Why refactoring".
I assume you have much better resources for that than this set of posts.

now that the extracted method became a one-liner (62 charaters long including the indentation) one might want to consider making it an inline statement.
I prefer it as a separate method for testing purposes.

* Actually we can shorten it to: "return _rentals.Sum((r) => r.GetCharge());"
As the type "Rental" is implied from _rentals.

Doing so for GetCharge and GetFrequentRenterPoints and - TADA!

Now the code for class Customer looks this way

using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Refactoring
{
public class Customer
{
public string Name { get; private set; }
List _rentals = new List();

public Customer(string name)
{
Name = name;
}

public void AddRental(Rental rental)
{
_rentals.Add(rental);
}

public string Statement()
{
IEnumerable rentals = _rentals;
string result = "Rental Record for " + Name + "\n";

foreach (Rental each in rentals)
{
// show figures for this rental
result += "\t" + each.Movie.Title + "\t" + each.GetCharge() + "\n";
}

// add footer
result += "Amount owed is " + GetTotalCharge() + "\n";
result += "You earned " + GetFrequentRenterPoints() + " frequent renter points";

return result;
}

public double GetTotalCharge()
{
return _rentals.Sum((r) => r.GetCharge());
}
public double GetFrequentRenterPoints()
{
return _rentals.Sum((r) => r.GetFrequentRentalPoints());
}
}
}
Hope you find it useful

Dekel

Thursday, December 23, 2010

How CSharp design patterns and refactoring differ from other languages - Part 02

This post continuing the post "How CSharp design patterns and refactoring differ from other languages - Part 01" and is based on Martin Fowler's "Refactoring" book.

For the refactoring explanation, please read the book, Marting Fowler explains it much better than I'll ever could. I'll concentrate of how it is done in CSharp.

So the first refactoring action in the book is "Extract Method" ( select the code from "double thidAmount = 0" till the end of the switch block, Menu --> Refactor --> Extract Method )
The automatic Extract-Method saves you the human errors such as double Vs. int, Yet - You always needed to test it and verify that the automation did what you expected it to do.

Next - renaming "each" to "aRental" (Not that I like this naming convention, but it is better than "each" and is is soon going away) and "thisAmount" --> "result"

And Moving Customer.AmountFor(Rental aRental) to Rental.GetCharge()
* You are missing the middle step - since I struggled with blogger editor html Vs WYSIWYG modes and lost some of the versions and my patience
---
using System.Collections;
using System.Collections.Generic;

namespace Refactoring
{
public class Customer
{
public string Name { get; private set; }
List _rentals = new List();

public Customer(string name)
{
Name = name;
}

public void AddRental(Rental rental)
{
_rentals.Add(rental);
}

public string Statement()
{
double totalAmount = 0;
int FrequentRenterPoints = 0;
IEnumerable rentals = _rentals;
string result = "Rental Record for " + Name + "\n";

foreach (Rental each in rentals)
{
double thisAmount = each.GetCharge();
// Add frequent renter points
FrequentRenterPoints++;
if (each.Movie.PriceCode == Movie.NEW_RELEASE &&
each.DaysRented > 1)
FrequentRenterPoints++;

// show figures for this rental
result += "\t" + each.Movie.Title + "\t" + thisAmount + "\n";
totalAmount += thisAmount;
}

// add footer
result += "Amount owed is " + totalAmount + "\n";
result += "You earned " + FrequentRenterPoints + " frequent renter points";

return result;
}
}
}
---

namespace Refactoring
{
public class Rental
{
public Movie Movie { get; private set; }
public int DaysRented { get; private set; }

public Rental(Movie movie, int daysRented)
{
Movie = movie;
DaysRented = daysRented;
}

public double GetCharge()
{
double result = 0;

// Determine amount for each line
switch (Movie.PriceCode)
{
case Movie.REGULAR:
result += 2;
if (DaysRented > 2)
result += (DaysRented - 2) * 1.5;
break;
case Movie.NEW_RELEASE:
result += DaysRented * 3;
break;
case Movie.CHILDRENS:
result += 1.5;
if (DaysRented > 3)
result += (DaysRented - 3) * 1.5;
break;
}

return result;
}
}
}
---

Tuesday, December 21, 2010

How CSharp design patterns and refactoring differ from other languages - Part 01

I'm reading Martin Fowler's "Refactoring" book, and recalling a course I had long ago about design patterns.

Now - these are extreamly useful tools, as you probably know, but...
When dealing with CSharp (and esspecially .Net 4.0) you have an extended set of tools that make some things so elegant it changes the way you can refactor and apply patterns.

The simplest example is "delegate" (and "anonymous delegate")
In the old-school of design patters we talk about classes and interfaces, while nowdays you can call the same method and pass it different worker delegate so easily, it changes the way you think about your code.

On the first chapter of Fowler's book (Where the examples are in Java) he shows extacting out a while statement that takes 6 lines of code, while using LINQ it would be a one-liner, and a readable one.

All of that said in order to explain that there should or at least could be a sub-version of both "Design Patterns" and "Refactoring" that is .Net specific and makes use of the great new features.

And now I need to get to work on getting the examples and translate them into CSharp.

So here is the initial code translated to CSharp
Note the different notation for class properties, Enumerations and const declerations
No deep change

---
namespace Refactoring
{
public class Movie
{
public const int CHILDRENS = 2;
public const int REGULAR = 0;
public const int NEW_RELEASE = 1;

public int PriceCode { get; set; }
public string Title { get; private set; }

public Movie(string title, int priceCode)
{
Title = title;
PriceCode = priceCode;
}
}
}
---
namespace Refactoring
{
public class Rental
{
public Movie Movie { get; private set; }
public int DaysRented { get; private set; }

public Rental(Movie movie, int daysRented)
{
Movie = movie;
DaysRented = daysRented;
}
}
}
---
using System.Collections;
using System.Collections.Generic;

namespace Refactoring
{
public class Customer
{
public string Name { get; private set; }
List _rentals = new List();

public Customer(string name)
{
Name = name;
}

public void AddRental(Rental rental)
{
_rentals.Add(rental);
}

public string Statement()
{
double totalAmount = 0;
int FrequentRenterPoints = 0;
IEnumerable rentals = _rentals;
string result = "Rental Record for " + Name + "\n";

foreach (Rental each in rentals)
{
double thisAmount = 0;

// Determine amount for each line
switch (each.Movie.PriceCode)
{
case Movie.REGULAR:
thisAmount += 2;
if (each.DaysRented > 2)
thisAmount += (each.DaysRented - 2) * 1.5;
break;
case Movie.NEW_RELEASE:
thisAmount += each.DaysRented * 3;
break;
case Movie.CHILDRENS:
thisAmount += 1.5;
if (each.DaysRented > 3)
thisAmount += (each.DaysRented - 3) * 1.5;
break;
}

// Add frequent renter points
FrequentRenterPoints++;
if (each.Movie.PriceCode == Movie.NEW_RELEASE &&
each.DaysRented > 1)
FrequentRenterPoints++;

// show figures for this rental
result += "\t" + each.Movie.Title + "\t" + thisAmount + "\n";
totalAmount += thisAmount;
}

// add footer
result += "Amount owed is " + totalAmount + "\n";
result += "You earned " + FrequentRenterPoints + " frequent renter points";

return result;
}
}
}
---

* Sorry for the missing indentation, you can paste it to VS and let it fix it

Let me know if you find this helpful.

Thursday, November 18, 2010

sc.exe problem Wrong return code

sc.ece version 5.2.3790.4455 does not return error code 1060 when querying non existing service

C:\>sc.exe query NonExistingServiceName
[SC] EnumQueryServicesStatus:OpenService FAILED 1060:

The specified service does not exist as an installed service.


C:\>echo %ErrorLevel%
0



While on other macine the same commands give error
c:\>sc.exe query NonExistingServiceName
[SC] EnumQueryServicesStatus:OpenService FAILED 1060:

The specified service does not exist as an installed service.


c:\>echo %ErrorLevel%
1060

just a little annoying thing

Wednesday, July 7, 2010

Amazon AWS EC2 S3 - experience

Recently I'm playing with EC2 images

Things are not trivial and different steps requires googling and trying things as the task is not a common one

1. Running on windows EC2 image (rather than linux)
2. Run task on instance startup (thather than at log in time)
- I expected this to be one of the mainstream tasks, but still found it hard to find "How to" about it
3. Automatically running instaces of an image
That should've been trivial, but AWS web interfaces has changed so old doc was misleading
Took me long time and some help to find to which cert they refer and how to match it to private key, to which one ... (this is behind me now)
4. S3 automation - currently using CloudBerry Explorer for Amazon
Boot task:
1. Task should run automatically w/o user logon
I used service for that, but I hope there is a simpler way, even though this is currently working for me.

Next thing is an S3 boot strapper ...

Saturday, November 1, 2008

יד שניה - אגורה

אתרי יד שניה בישראל

לעניות דעתי הבלתי קובעת - מסירת חפצים ושימוש בחפצים מיד שניה הם דבר חיובי מכמה בחינות:

  1. איכות הסביבה


  2. פחות הוצאות


  3. תרמה לזולת (יותר מודעות)

אני מכיר את אתר אגורה ומאוד ממליץ






אשמח לקבל המלצות על אתרים נודפים וחנויות יד שניה

Tuesday, September 9, 2008

Getting into LINQ and error CS0742 (101 LINQ samples)

While checking what can be done with LINQ using the samples at:
http://msdn.microsoft.com/en-us/vcsharp/aa336758.aspx#SelectSimple1

I bumped into compile error:
error CS0742: A query body must end with a select clause or a group clause

Searching the web did not give good answer (only one saying this is not the correct syntax)

I had to go the VS help for select and From statemens titled: "from clause (C# Reference)"

  • The wrong syntax:
    from a in numbersA, b in numbersB
  • The correct syntax:
    from a in numbersA from b in numbersB
HTH

Dekel