Better way to do this in C# 2003?

G

Guest

Hi,

I have two simple classes called 'User' and 'Users', the entire code for
both classes is shown below.

****======== User.cs ========****

public class User
{
private string _displayName, _email;
private bool _approved;

public User(string displayName, string email, bool approved)
{
this._displayName = displayName;
this._email = email;
this._approved = _approved;
}

public string DisplayName
{
get { return _displayName; }
}

public string Email
{
get { return _email; }
}

public bool Approved
{
get { return _approved; }
}
}

****======== Users.cs ========****

public class Users : System.Collections.CollectionBase
{
public User this[int index]
{
get { return (User)(List[index]); }
set { List[index] = value; }
}

public Users FilterByDisplayName(string criteria, bool exclude)
{
Users _tmp;
if (exclude)
{
_tmp = this.Clone();
foreach (User _user in this)
{
if (_user.DisplayName.IndexOf(criteria) >= 0)
_tmp.Remove(_user);
}
}
else
{
_tmp = new Users();
foreach (User _user in this)
{
if (_user.DisplayName.IndexOf(criteria) >= 0)
_tmp.Add(_user);
}
}
return _tmp;
}

public Users FilterByEmail(string criteria, bool exclude)
{
Users _tmp;
if (exclude)
{
_tmp = this.Clone();
foreach (User _user in this)
{
if (_user.Email.IndexOf(criteria) >= 0)
_tmp.Remove(_user);
}
}
else
{
_tmp = new Users();
foreach (User _user in this)
{
if (_user.Email.IndexOf(criteria) >= 0)
_tmp.Add(_user);
}
}
return _tmp;
}

public Users FilterByApproved(bool criteria, bool exclude)
{
Users _tmp;
if (exclude)
{
_tmp = this.Clone();
foreach (User _user in this)
{
if (_user.Approved == criteria)
_tmp.Remove(_user);
}
}
else
{
_tmp = new Users();
foreach (User _user in this)
{
if (_user.Approved == criteria)
_tmp.Add(_user);
}
}
return _tmp;
}

public Users Clone()
{
Users _tmp = new Users();
foreach (User _user in this)
{
_tmp.Add(_user);
}
return _tmp;
}

public int Add(User value)
{
return List.Add(value);
}

public void Remove(User value)
{
List.Remove(value);
}
}

On the 'Users' class I have three methods (FilterByDisplayName,
FilterByEmail and FilterByApproved) which basically do the same thing except
they work on a different field on the 'User' class, and in the case of
FilterByApproved on a different data type (bool instead of string). I cannot
find an elegant way to combine these three methods into one method called
Filter(), is there an elegant way of combining these three methods into one
using C# 2003?

Many Thanks,

Peter
 
M

Michael C

Hi,

I have two simple classes called 'User' and 'Users', the entire code for
both classes is shown below.

One thing I noticed was you could do something like this

if ((_user.DisplayName.IndexOf(criteria) >= 0) != Exclude)

As for combining them into one function you could create a comparison
function and pass this in as a delegate or an interface, similar to the
IComparer interface, see help on ArrayList.Sort

Michael
 
G

Guest

Hi Michael,

Thanks for the reply, I have tried passing in a delegate to a Filter method
and using this to call the function that actually does the filter. But this
still means I have to have the three methods that actually perform the
filtering, the delegate passed in would just point to one of the three
functions.

Regards,

Peter
 
M

Michael C

Peter said:
Hi Michael,

Thanks for the reply, I have tried passing in a delegate to a Filter
method
and using this to call the function that actually does the filter. But
this
still means I have to have the three methods that actually perform the
filtering, the delegate passed in would just point to one of the three
functions.

That's correct but the three functions are essentially different (2 are just
co-incidentally the same I'd suggest) and should probably be 3 seperate
functions. The other option is to pass in a delegate to the property on the
object and have the function smart enought to deal with the different return
types. Or have the properties on the object passed out of an indexer.

Michael
 
G

Guest

Hi Peter,
I would abstract out the idea of filtering from the collection class, so
that the logic for filtering lives inside a different object say a UserFilter
class, this class would have one method called Filter which takes a user as a
parameter. The filter method would then return true if the user met the
criteria and false otherwise. You would then have deriviations of this class
like NameFilter, EmailFilter and ApprovedFilter.

Your Users class would then have one function called Filter which then takes
a UserFilter as a parameter i.e. Filter(UserFilter filter).

See the example below (the formatting might be a bit messed up):

using System;

namespace ConsoleApplication11
{

/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
User userMark, userBob, userFrank;

userMark = new User("mark", "(e-mail address removed)", true);
userBob = new User("bob", "(e-mail address removed)", true);
userFrank = new User("frank", "(e-mail address removed)", false);

Users userCollection = new Users();
userCollection.Add(userMark);
userCollection.Add(userBob);
userCollection.Add(userFrank);

NameFilter nameFilter = new NameFilter("mark");
Users usersFilteredByName = userCollection.Filter(nameFilter, true);

EmailFilter emailFilter = new EmailFilter("(e-mail address removed)");
Users usersFilteredByEmail = userCollection.Filter(emailFilter, true);

ApprovalFilter approvalFilter = new ApprovalFilter(true);
Users usersFilteredByApproval = userCollection.Filter(approvalFilter, true);

Console.ReadLine();
}
}


public abstract class UserFilter
{
protected string _criteria;

protected UserFilter(){}

protected UserFilter(string criteria)
{
_criteria = criteria;
}

public abstract bool Filter(User u);
}

public class NameFilter : UserFilter
{
public NameFilter(string criteria) : base(criteria)
{}

public override bool Filter(User u)
{
return u.DisplayName.IndexOf(_criteria) >= 0;
}
}

public class EmailFilter : UserFilter
{
public EmailFilter(string criteria) : base(criteria)
{}

public override bool Filter(User u)
{
return u.Email.IndexOf(_criteria) >= 0;
}
}

public class ApprovalFilter : UserFilter
{
private bool _approvalCriteria;
public ApprovalFilter(bool criteria)
{
_approvalCriteria = criteria;
}

public override bool Filter(User u)
{
return u.Approved == _approvalCriteria;
}
}



public class User
{
private string _displayName, _email;
private bool _approved;

public User(string displayName, string email, bool approved)
{
this._displayName = displayName;
this._email = email;
this._approved = approved;
}

public string DisplayName
{
get { return _displayName; }
}

public string Email
{
get { return _email; }
}

public bool Approved
{
get { return _approved; }
}
}


public class Users : System.Collections.CollectionBase
{
public User this[int index]
{
get { return (User)(List[index]); }
set { List[index] = value; }
}

public Users Filter(UserFilter filter, bool exclude)
{
Users _tmp;
if (exclude)
{
_tmp = this.Clone();
foreach (User _user in this)
{
if (filter.Filter(_user))
{
_tmp.Remove(_user);
}
}
}
else
{
_tmp = new Users();
foreach (User _user in this)
{
if (filter.Filter(_user))
{
_tmp.Add(_user);
}
}
}
return _tmp;
}

public Users Clone()
{
Users _tmp = new Users();
foreach (User _user in this)
{
_tmp.Add(_user);
}
return _tmp;
}

public int Add(User value)
{
return List.Add(value);
}

public void Remove(User value)
{
List.Remove(value);
}
}

}


Also, there was a small error in the code you published, in the
constructor you have:
public User(string displayName, string email, bool approved)
{
this._displayName = displayName;
this._email = email;
this._approved = _approved;
}

you need to change the appoved line to say:
this._approved = approved not this._approved = _approved


Hope that helps
Mark R Dawson
http://www.markdawson.org



Peter said:
Hi,

I have two simple classes called 'User' and 'Users', the entire code for
both classes is shown below.

****======== User.cs ========****

public class User
{
private string _displayName, _email;
private bool _approved;

public User(string displayName, string email, bool approved)
{
this._displayName = displayName;
this._email = email;
this._approved = _approved;
}

public string DisplayName
{
get { return _displayName; }
}

public string Email
{
get { return _email; }
}

public bool Approved
{
get { return _approved; }
}
}

****======== Users.cs ========****

public class Users : System.Collections.CollectionBase
{
public User this[int index]
{
get { return (User)(List[index]); }
set { List[index] = value; }
}

public Users FilterByDisplayName(string criteria, bool exclude)
{
Users _tmp;
if (exclude)
{
_tmp = this.Clone();
foreach (User _user in this)
{
if (_user.DisplayName.IndexOf(criteria) >= 0)
_tmp.Remove(_user);
}
}
else
{
_tmp = new Users();
foreach (User _user in this)
{
if (_user.DisplayName.IndexOf(criteria) >= 0)
_tmp.Add(_user);
}
}
return _tmp;
}

public Users FilterByEmail(string criteria, bool exclude)
{
Users _tmp;
if (exclude)
{
_tmp = this.Clone();
foreach (User _user in this)
{
if (_user.Email.IndexOf(criteria) >= 0)
_tmp.Remove(_user);
}
}
else
{
_tmp = new Users();
foreach (User _user in this)
{
if (_user.Email.IndexOf(criteria) >= 0)
_tmp.Add(_user);
}
}
return _tmp;
}

public Users FilterByApproved(bool criteria, bool exclude)
{
Users _tmp;
if (exclude)
{
_tmp = this.Clone();
foreach (User _user in this)
{
if (_user.Approved == criteria)
_tmp.Remove(_user);
}
}
else
{
_tmp = new Users();
foreach (User _user in this)
{
if (_user.Approved == criteria)
_tmp.Add(_user);
}
}
return _tmp;
}

public Users Clone()
{
Users _tmp = new Users();
foreach (User _user in this)
{
_tmp.Add(_user);
}
return _tmp;
}

public int Add(User value)
{
return List.Add(value);
}

public void Remove(User value)
{
List.Remove(value);
}
}

On the 'Users' class I have three methods (FilterByDisplayName,
FilterByEmail and FilterByApproved) which basically do the same thing except
they work on a different field on the 'User' class, and in the case of
FilterByApproved on a different data type (bool instead of string). I cannot
find an elegant way to combine these three methods into one method called
Filter(), is there an elegant way of combining these three methods into one
using C# 2003?

Many Thanks,

Peter
 
G

Guest

Awesome, your solution is what the word elegant was invented for :->

Cheers,

Peter


Mark R. Dawson said:
Hi Peter,
I would abstract out the idea of filtering from the collection class, so
that the logic for filtering lives inside a different object say a UserFilter
class, this class would have one method called Filter which takes a user as a
parameter. The filter method would then return true if the user met the
criteria and false otherwise. You would then have deriviations of this class
like NameFilter, EmailFilter and ApprovedFilter.

Your Users class would then have one function called Filter which then takes
a UserFilter as a parameter i.e. Filter(UserFilter filter).

See the example below (the formatting might be a bit messed up):

using System;

namespace ConsoleApplication11
{

/// <summary>
/// Summary description for Class1.
/// </summary>
class Class1
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
User userMark, userBob, userFrank;

userMark = new User("mark", "(e-mail address removed)", true);
userBob = new User("bob", "(e-mail address removed)", true);
userFrank = new User("frank", "(e-mail address removed)", false);

Users userCollection = new Users();
userCollection.Add(userMark);
userCollection.Add(userBob);
userCollection.Add(userFrank);

NameFilter nameFilter = new NameFilter("mark");
Users usersFilteredByName = userCollection.Filter(nameFilter, true);

EmailFilter emailFilter = new EmailFilter("(e-mail address removed)");
Users usersFilteredByEmail = userCollection.Filter(emailFilter, true);

ApprovalFilter approvalFilter = new ApprovalFilter(true);
Users usersFilteredByApproval = userCollection.Filter(approvalFilter, true);

Console.ReadLine();
}
}


public abstract class UserFilter
{
protected string _criteria;

protected UserFilter(){}

protected UserFilter(string criteria)
{
_criteria = criteria;
}

public abstract bool Filter(User u);
}

public class NameFilter : UserFilter
{
public NameFilter(string criteria) : base(criteria)
{}

public override bool Filter(User u)
{
return u.DisplayName.IndexOf(_criteria) >= 0;
}
}

public class EmailFilter : UserFilter
{
public EmailFilter(string criteria) : base(criteria)
{}

public override bool Filter(User u)
{
return u.Email.IndexOf(_criteria) >= 0;
}
}

public class ApprovalFilter : UserFilter
{
private bool _approvalCriteria;
public ApprovalFilter(bool criteria)
{
_approvalCriteria = criteria;
}

public override bool Filter(User u)
{
return u.Approved == _approvalCriteria;
}
}



public class User
{
private string _displayName, _email;
private bool _approved;

public User(string displayName, string email, bool approved)
{
this._displayName = displayName;
this._email = email;
this._approved = approved;
}

public string DisplayName
{
get { return _displayName; }
}

public string Email
{
get { return _email; }
}

public bool Approved
{
get { return _approved; }
}
}


public class Users : System.Collections.CollectionBase
{
public User this[int index]
{
get { return (User)(List[index]); }
set { List[index] = value; }
}

public Users Filter(UserFilter filter, bool exclude)
{
Users _tmp;
if (exclude)
{
_tmp = this.Clone();
foreach (User _user in this)
{
if (filter.Filter(_user))
{
_tmp.Remove(_user);
}
}
}
else
{
_tmp = new Users();
foreach (User _user in this)
{
if (filter.Filter(_user))
{
_tmp.Add(_user);
}
}
}
return _tmp;
}

public Users Clone()
{
Users _tmp = new Users();
foreach (User _user in this)
{
_tmp.Add(_user);
}
return _tmp;
}

public int Add(User value)
{
return List.Add(value);
}

public void Remove(User value)
{
List.Remove(value);
}
}

}


Also, there was a small error in the code you published, in the
constructor you have:
public User(string displayName, string email, bool approved)
{
this._displayName = displayName;
this._email = email;
this._approved = _approved;
}

you need to change the appoved line to say:
this._approved = approved not this._approved = _approved


Hope that helps
Mark R Dawson
http://www.markdawson.org



Peter said:
Hi,

I have two simple classes called 'User' and 'Users', the entire code for
both classes is shown below.

****======== User.cs ========****

public class User
{
private string _displayName, _email;
private bool _approved;

public User(string displayName, string email, bool approved)
{
this._displayName = displayName;
this._email = email;
this._approved = _approved;
}

public string DisplayName
{
get { return _displayName; }
}

public string Email
{
get { return _email; }
}

public bool Approved
{
get { return _approved; }
}
}

****======== Users.cs ========****

public class Users : System.Collections.CollectionBase
{
public User this[int index]
{
get { return (User)(List[index]); }
set { List[index] = value; }
}

public Users FilterByDisplayName(string criteria, bool exclude)
{
Users _tmp;
if (exclude)
{
_tmp = this.Clone();
foreach (User _user in this)
{
if (_user.DisplayName.IndexOf(criteria) >= 0)
_tmp.Remove(_user);
}
}
else
{
_tmp = new Users();
foreach (User _user in this)
{
if (_user.DisplayName.IndexOf(criteria) >= 0)
_tmp.Add(_user);
}
}
return _tmp;
}

public Users FilterByEmail(string criteria, bool exclude)
{
Users _tmp;
if (exclude)
{
_tmp = this.Clone();
foreach (User _user in this)
{
if (_user.Email.IndexOf(criteria) >= 0)
_tmp.Remove(_user);
}
}
else
{
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top