For the past two hours I've been trying to experiment with delegates / events - my aim is to inform users with both the previous book name and new book as a new book name is set.
However, in all cases in my Abstract class, NameChanged(args.ExistingName, args.NewNames); returns null. I can't seem to figure out why, I have tried manually passing through two string params yet visual studio throws an error stating that NameChanged contains a null value.
internal interface Iinterface
{
void AddContact(string name, string number);
void RemoveContact(string name);
void RetrieveContacts();
void RetrieveByName(string name);
void RetrieveByNumber(string number);
string Name { get; set; }
}
public abstract class Abstract : Iinterface
{
public abstract void AddContact(string name, string number);
public abstract void RemoveContact(string name);
public abstract void RetrieveContacts();
public abstract void RetrieveByName(string name);
public abstract void RetrieveByNumber(string number);
public string Name{
get
{
return _name;
}
set
{
NameChangedEventArgs args = new NameChangedEventArgs();
args.ExistingName = _name;
args.NewName = value;
NameChanged(args.ExistingName, args.NewName); // this refers to the abstract class?
_name = value;
}
}
public NameChangedEventHandler NameChanged; // I presume here we're taking an instance of the delegate method.
protected string _name;
}
public class PhoneBook : Abstract
{
public PhoneBook()
{
_name = "phone book name";
}
public override void AddContact(string name, string number)
{
contacts.Add(name, number);
}
public override void RemoveContact(string name)
{
contacts.Remove(name);
}
public override void RetrieveContacts()
{
foreach (KeyValuePair<string, string> entry in contacts)
{
Console.WriteLine("Name : {0} Number : {1}", entry.Key, entry.Value);
}
}
public override void RetrieveByName(string name)
{
foreach(KeyValuePair<string, string> entry in contacts)
{
if(entry.Key == name)
{
Console.WriteLine("Name : {0} Number : {1}", entry.Key, entry.Value);
}
}
}
public override void RetrieveByNumber(string number)
{
foreach(KeyValuePair<String,string> entry in contacts)
{
if (entry.Value == number)
{
Console.WriteLine("Name : {0} Number : {1}", entry.Key, entry.Value);
}
}
}
Dictionary<string, string> contacts = new Dictionary<string, string>();
}
public class NameChangedEventArgs : EventArgs
{
public string ExistingName { get; set; }
public string NewName { get; set; }
}
{
// public delegate void NameChangedEventHandler(object sender, NameChangedEventArgs args);
public delegate void NameChangedEventHandler(string existingName, string newName);
}
class Program
{
static void Main(string[] args)
{
PhoneBook book = new PhoneBook();
setName(book);
addContact(book);
retrieveByName(book);
retrieveByNumber(book);
book.NameChanged = new NameChangedEventHandler(OnNameChanged); // call OnNameChanged whenever someone invokes this delegate
Console.ReadLine();
/* book.retrieveContacts(); */
}
private static void setName(PhoneBook book)
{
book.Name = "book name";
Console.WriteLine(book.Name);
}
private static void retrieveByNumber(PhoneBook book)
{
book.RetrieveByNumber("0323242389");
}
private static void retrieveByName(PhoneBook book)
{
book.RetrieveByName("james");
}
private static void addContact(PhoneBook book)
{
book.AddContact("james", "0151289");
book.AddContact("Bob", "0323242389");
book.AddContact("Hannah", "34234");
}
static void OnNameChanged(string existingName, string newName)
{
Console.WriteLine($"Gradebook changing name from {existingName} to {newName}");
}
}
For registering a delegate or event with a method, the following is the syntax for it:
book.NameChanged+= new NameChangedEventHandler(OnNameChanged);
and Secondly you should not be invoking it blindly at invoking side.
you should be checking if someone has subscribed to it or any method is assigned to it like:
if(NameChanged !=null)
NameChanged(args.ExistingName, args.NewName);
or in c# 6:
NameChanged?.Invoke(args.ExistingName, args.NewName);
Hope it helps you.
Related
I have a ParentClass. Two classes are inherit from it, FirstChildClass and SecondChildClass. A class MultipleValueTypes contains a Dictionary and a method that adds values to it. My intention is to be able to pass values of different classes, which inherit from the same abstract class to the value parameter of the Dictionary. Therefore, I initialize the dictionary with the value List<ParentClass> so that I would be able to add objects made with the child classes to the Dictionary. I can do this, but I cannot access them, therefore in the abstract class I create a way to tell them apart, a virtual method that both the children classes override to return their own class type.
I test the values they return against the enum itself and based on whether the condition is fulfilled, the object would be casted as what it is instead of a List<ParentClass>. Is this the wrong approach? Is this impossible?
I think it should work, because in my thinking the FirstObject and SecondObject are still objects of their respective classes, so casting should work and I should be able to access the overridden method.
What doesn't work: I cannot access the method that returns what type of class it is, because it only gets methods from the List<ParentClass>.
What I've tried so far: searching for a way to access the method, but I did not find any.
What I still need help with: everything mentioned above.
public abstract class ParentClass
{
public string Name { get; set; }
public ParentClass(string Name)
{
this.Name = Name;
}
public enum ChildClasses
{
NoChildClass = 0,
FirstChildClass = 1,
SecondChildClass = 2
}
public virtual ChildClasses TypeOfClass()
{
return ChildClasses.NoChildClass;
}
}
public class FirstChildClass : ParentClass
{
private string _randomvalue;
public string RandomValue { get => _randomvalue; set => _randomvalue = value; }
public FirstChildClass(string Name) : base(Name)
{
}
public void ReturnMessage()
{
Console.WriteLine("This is the FirstChildClass");
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.FirstChildClass;
}
}
public class SecondChildClass : ParentClass
{
private string _randomvalue;
public string RandomValue { get => _randomvalue; set => _randomvalue = value; }
public SecondChildClass(string Name) : base(Name)
{
}
public void ReturnMessage()
{
Console.WriteLine("This is the SecondChildClass");
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.SecondChildClass;
}
}
class MultipleValueTypes
{
public Dictionary<string, List<ParentClass>> ADictionary = new Dictionary<string, List<ParentClass>>();
public void AddObject(string Name, ParentClass variable)
{
if (!ADictionary.ContainsKey(Name))
{
ADictionary.Add(Name, new List<ParentClass>());
}
ADictionary[Name].Add(variable);
}
}
class Program
{
static void Main(string[] args)
{
FirstChildClass FirstObject = new FirstChildClass("FirstObject");
SecondChildClass SecondObject = new SecondChildClass("SecondObject");
MultipleValueTypes TestDictionary = new MultipleValueTypes();
TestDictionary.AddObject("FirstObject", FirstObject);
TestDictionary.AddObject("SecondObject", SecondObject);
if(TestDictionary.ADictionary["FirstObject"].TypeOfClass() == ParentClass.ChildClasses.FirstChildClass) ///List<ParentClass>' does not contain a definition for 'TypeOfClass' and no accessible extension method 'TypeOfClass' accepting a first argument of type 'List<ParentClass>' could be found (are you missing a using directive or an assembly reference?)
{
TestDictionary.ADictionary["FirstObject"] = (FirstChildClass)TestDictionary.ADictionary["FirstObject"]; ///Cannot convert type 'System.Collections.Generic.List<Dictionary.ParentClass>' to 'Dictionary.FirstChildClass
}
}
}
You forgot to use indexer of the list value of the key of the dictionary here:
==> TestDictionary.ADictionary["FirstObject"][0]
Here is your code now refactored too:
class Program
{
static void Main(string[] args)
{
var FirstObject = new FirstChildClass("FirstObject");
var SecondObject = new SecondChildClass("SecondObject");
FirstObject.ReturnMessage();
SecondObject.ReturnMessage();
MultipleValueTypes TestDictionary = new MultipleValueTypes();
TestDictionary.AddObject("FirstObject", FirstObject);
TestDictionary.AddObject("SecondObject", SecondObject);
if ( TestDictionary.ADictionary["FirstObject"][0].TypeOfClass()
== ParentClass.ChildClasses.FirstChildClass )
{
TestDictionary.ADictionary["FirstObject"][0]
= (FirstChildClass)TestDictionary.ADictionary["FirstObject"][0];
}
Console.ReadKey();
}
}
public abstract class ParentClass
{
public string Name { get; set; }
public string RandomValue { get; set; }
public ParentClass(string Name)
{
this.Name = Name;
}
public virtual void ReturnMessage()
{
Console.WriteLine($"This is the {this.GetType().Name} instance");
}
public virtual ChildClasses TypeOfClass()
{
return ChildClasses.NoChildClass;
}
public enum ChildClasses
{
NoChildClass = 0,
FirstChildClass = 1,
SecondChildClass = 2
}
}
public class FirstChildClass : ParentClass
{
public FirstChildClass(string Name)
: base(Name)
{
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.FirstChildClass;
}
}
public class SecondChildClass : ParentClass
{
public SecondChildClass(string Name)
: base(Name)
{
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.SecondChildClass;
}
}
class MultipleValueTypes
{
public readonly Dictionary<string, List<ParentClass>> ADictionary
= new Dictionary<string, List<ParentClass>>();
public void AddObject(string Name, ParentClass variable)
{
if ( !ADictionary.ContainsKey(Name) )
{
ADictionary.Add(Name, new List<ParentClass>());
}
ADictionary[Name].Add(variable);
}
}
If the intention is to cast the whole list from List<ParentClass> to List<FirstChildClass> and List<SecondChildClass>, then Linq is your friend, just use the Cast function:
List<FirstChildClass> firstChildClasses = TestDictionary.ADictionary["FirstObject"]
.Cast<FirstChildClass>().ToList();
List<SecondChildClass> secondChildClasses = TestDictionary.ADictionary["SecondObject"]
.Cast<SecondChildClass>().ToList();
I have multiple classes containing duplicated code, especially members and most important a static method that will create a new instance of the class and returning this instance: either a previously created instance registered in a dictionary or a new instance by calling the constructor.
An interface is no option, because I have the static method. I tried to solve the problem by introducing a base class that implements this static method, but I can not find a way to create and return a spefific child class properly.
Below is a code example of the current situation with class A and class B showing duplicated code.
public class A
{
private static readonly IDictionary<string, A> Registry = new Dictionary<string, A>();
public string Name { get; set; }
public A(string name)
{
this.Name = name;
}
public static A GetA(string instanceName)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = new A(instanceName);
}
return newInstance;
}
}
}
And then in class B again there is a member Name and the GetX() Method.
public class B
{
private static readonly IDictionary<string, B> Registry = new Dictionary<string, B>();
public string Name { get; set; }
public B(string name)
{
this.Name = name;
}
public static B GetB(string instanceName)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = new B(instanceName);
}
return newInstance;
}
}
}
Is there a possibility to avoid this kind of code duplication by introducing a base class or any other way?
This might be a little cleaner:
public class B: RegistryInstance<B>
{
public string Name { get; set; }
public B(string name)
{
this.Name = name;
}
}
public class A : RegistryInstance<A>
{
public string Name { get; set; }
public A(string name)
{
this.Name = name;
}
}
public abstract class RegistryInstance<T> where T:class
{
protected static readonly IDictionary<string, T> Registry = new Dictionary<string, T>();
public static T GetInstance(string instanceName)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = (T)Activator.CreateInstance(typeof(T), new object[] { instanceName });
Registry.Add(instanceName, newInstance);
}
return newInstance;
}
}
}
Are you looking for a generic base class?
public abstract class BaseRegistryGetter<T>
{
private static readonly IDictionary<string, T> Registry = new Dictionary<string, T>();
public string Name { get; set; }
public BaseRegistryGetter(string name)
{
this.Name = name;
}
public static T GetValue (string instanceName, Func<string, T> creator) {
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = creator(instanceName);
}
return newInstance;
}
}
}
And then use it like this:
public class A : BaseRegistryGetter<A>
{
public A(string name) : base(name)
{
}
public static A GetA(string instanceName)
{
return BaseRegistryGetter<A>.GetValue(instanceName, s => new A(s));
}
}
The source for the awkward approach to make sure there is a string-constructor for A can be found here.
I think this should work. You can adapt it to fit your needs. Also, there was a bug in your code: you forgot to add to the Registry when you were creating a new instance.
class Program
{
static void Main(string[] args)
{
A a1 = A.GetInstance("a");
A a2 = A.GetInstance("aa");
A a3 = A.GetInstance("a");
B b1 = B.GetInstance("a");
B b2 = B.GetInstance("aa");
B b3 = B.GetInstance("a");
Console.WriteLine(a1 == a2); //false
Console.WriteLine(a1 == a3); //true
Console.WriteLine(b1 == b2); //false
Console.WriteLine(b1 == b3); //true
Console.ReadKey();
}
}
public class A : Generic<A>
{
public A(string name)
: base(name)
{
}
}
public class B : Generic<B>
{
public B(string name)
: base(name)
{
}
}
public abstract class Generic<T> where T : Generic<T>
{
private static readonly IDictionary<string, T> Registry = new Dictionary<string, T>();
public string Name { get; set; }
public Generic(string name)
{
this.Name = name;
}
public static T GetInstance(string instanceName)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = (T)Activator.CreateInstance(typeof(T), instanceName);
Registry.Add(instanceName, newInstance);
}
return newInstance;
}
}
}
All the other answers try to solve this with generics, but it might be the case you wouldn't want to do this. First, it could be an unnecessary restriction further along that could end up causing variance issues. Second, it only solves one level of inheritance, if there is more, you are stuck again with the same problem:
class Base<T> { ... }
class A: Base<A> { ... }
class B: A { //How does the generic base class help? }
There are general solutions without the use generics that entails just a little code duplication. One could be the following:
public class Base
{
static readonly IDictionary<string, Base> Registry =
new Dictionary<string, Base>();
protected static Base GetBase(string instanceName,
Func<Base> creator)
{
lock (Registry)
{
if (!Registry.TryGetValue(instanceName, out var newInstance))
{
newInstance = creator();
}
return newInstance;
}
}
//...
}
And now yor derived types can impement a strongly typed delegated method:
public class A: Base
{
public A(string instanceName)
:base(instanceName)
{
}
public static A GetA(string instanceName)
=> GetBase(instanceName, () => new A(instanceName)) as A;
}
public class B: Base
{
public B(string instanceName)
:base(instanceName)
{
}
public static B GetB(string instanceName)
=> GetBase(instanceName, () => new B(instanceName)) as B;
}
I want to add an observer in my model, i try to generic delegate but here is problem when invoke.
Here is my code and it works when I use 'handler.DynamicInvoke(this)' instead of 'Invoke'
but I know DynamicInvoke is slow... I want to know is here a right way to use Invoke.
public class Model<T>
{
public delegate void UpdatePrototype<T>(T mdl);
private List<UpdatePrototype<T>> listeners = new List<UpdatePrototype<T>>();
public void Bind(UpdatePrototype<T> handler)
{
listeners.Add(handler);
}
public void Sync()
{
foreach(UpdatePrototype<T> handler in listeners)
{
handler.Invoke((T)this); // << ERROR: can not convert Model<T> to T
}
}
public string Name = "Model";
}
public class MyModel : Model<MyModel>
{
public string Name = "MyModel";
}
public class YourModel : Model<YourModel>
{
public string Name = "YourModel";
}
void Main()
{
MyModel mdl = new MyModel();
mdl.Bind(MyUpdate);
mdl.Sync();
YourModel your = new YourModel();
your.Bind(YourUpdate);
your.Sync();
}
void MyUpdate(MyModel mdl)
{
Debug.Log(mdl.Name);
}
void YourUpdate(YourModel mdl)
{
Debug.Log(mdl.Name);
}
============
thanks #IVAAAN123 i modify my code as follow.
it is fine for me, although mdl.Sync<MyModel>() has a little odd ;)
public class Model<T>
{
public delegate void UpdatePrototype<T>(T mdl);
private List<UpdatePrototype<T>> listeners = new List<UpdatePrototype<T>>();
public void Bind(UpdatePrototype<T> handler)
{
listeners.Add(handler);
}
public void Sync()
{
foreach(UpdatePrototype<T> handler in listeners)
{
handler.DynamicInvoke(this);
}
}
public void Sync<T>() where T : Model<T>
{
foreach(UpdatePrototype<T> handler in listeners)
{
handler.Invoke((T)this);
}
}
public string Name = "Model";
}
public class MyModel : Model<MyModel>
{
public string Name = "MyModel";
}
public class YourModel : Model<YourModel>
{
public string Name = "YourModel";
}
void Main()
{
MyModel mdl = new MyModel();
mdl.Bind(MyUpdate);
mdl.Sync<MyModel>();
mdl.Sync();
YourModel your = new YourModel();
your.Bind(YourUpdate);
your.Sync<YourModel>();
your.Sync();
}
void MyUpdate(MyModel mdl)
{
Debug.Log(mdl.Name);
}
void YourUpdate(YourModel mdl)
{
Debug.Log(mdl.Name);
}
}
public class Model<T>
{
public delegate void UpdatePrototype<S>(S mdl);
private List<UpdatePrototype<Model<T>>> listeners = new List<UpdatePrototype<Model<T>>>();
public void Bind(UpdatePrototype<Model<T>> handler)
{
listeners.Add(handler);
}
public void Sync()
{
foreach (UpdatePrototype<Model<T>> handler in listeners)
{
handler(this);
}
}
public virtual string Name
{
get
{
return "Model";
}
}
}
public class MyModel : Model<MyModel>
{
public override string Name
{
get
{
return "MyModel";
}
}
}
public class YourModel : Model<YourModel>
{
public override string Name
{
get
{
return "YourModel";
}
}
}
void main()
{
MyModel mdl = new MyModel();
mdl.Bind(MyUpdate);
mdl.Sync();
YourModel your = new YourModel();
your.Bind(YourUpdate);
your.Sync();
}
void MyUpdate(Model<MyModel> mdl)
{
Console.WriteLine("MY MODEL HANDLER");
Console.WriteLine(mdl.Name);
}
void YourUpdate(Model<YourModel> mdl)
{
Console.WriteLine("YOUR MODEL HANDLER");
Console.WriteLine(mdl.Name);
}
I have the following code for supporting a list of different types :
public enum eType
{
tInt,
tString,
tDateTime
}
public interface ICustomType<out T>
{
T Value { get; }
}
public abstract class DifferentType
{
protected DifferentType(eType type, string mnemonic)
{
Type = type;
Mnemonic = mnemonic;
}
public string Mnemonic { get; private set; }
public eType Type { get; private set; }
}
public class DateTimeType : DifferentType, ICustomType<DateTime>
{
public DateTimeType(DateTime value, string mnemonic)
: base(eType.tDateTime, mnemonic)
{
Value = value;
}
public DateTime Value { get; private set; }
}
public class IntType : DifferentType, ICustomType<int>
{
public IntType(int value, string mnemonic)
: base(eType.tInt, mnemonic)
{
Value = value;
}
public int Value { get; private set; }
}
public class StringType : DifferentType, ICustomType<string>
{
public StringType(string value, string mnemonic)
: base(eType.tString, mnemonic)
{
Value = value;
}
public string Value { get; private set; }
}
public static class UtilValue
{
public static T GetValue<T>(DifferentType customType)
{
return ((ICustomType<T>)customType).Value;
}
}
public class testTypes2
{
public testTypes2()
{
var values = new List<DifferentType> { GetInt(), GetString(), GetDate() };
foreach (var i in values)
{
switch (i.Type)
{
case eType.tInt:
int resInt = UtilValue.GetValue<int>(i);
break;
case eType.tString:
string resString = UtilValue.GetValue<string>(i);
break;
case eType.tDateTime:
DateTime resDateTime = UtilValue.GetValue<DateTime>(i);
break;
}
}
}
private DateTimeType GetDate()
{
return new DateTimeType(new DateTime(2000, 1, 1), "MnemonicDate");
}
private IntType GetInt()
{
return new IntType(5, "MnemonicInt");
}
private StringType GetString()
{
return new StringType("ok", "MnemonicString");
}
}
and would like to avoid the cast at line return ((ICustomType<T>)customType).Value; in the UtilValue class, any idea how I can get rid of that while still keeping the design?
I am not even sure if this cast is expensive to do? My guess is most certainly.
Visitor-pattern example:
interface IDifferentTypeVisitor
{
void Visit(DateTimeType dt);
void Visit(StringType st);
}
class DifferentType
{
public abstract void Accept(IDifferentTypeVisitor visitor);
}
class DateTimeType : DifferentType
{
public void Accept(IDifferentTypeVisitor visitor)
{
visitor.Visit(this);
}
}
class StringType : DifferentType
{
public void Accept(IDifferentTypeVisitor visitor)
{
visitor.Visit(this);
}
}
class SomeVisitor : IDifferentTypeVisitor
{
public void Visit(DateTimeType dt)
{
//DateTime resDateTime = dt.Value; Or similar
}
public void Visit(StringType st)
{
//string resString = st.Value; Or similar
}
}
public class testTypes2
{
public testTypes2()
{
var values = new List<DifferentType> { /* Content */ };
var visitor = new SomeVisitor();
foreach (var i in values)
{
i.Accept(visitor);
}
}
}
In C# 4 with dynamic it's possible to save some code by adding this to DifferentType:
public void Accept(IDifferentTypeVisitor visitor)
{
visitor.Visit((dynamic)this);
}
and then delete all other Accept methods. It hurts performance but it looks better ;-)
So I want to design a team/player relationship like this: every player belongs to one team but since I wanted to practice with interfaces I made ITeam and IAthlete and then made BasketballTeam and BasketballPlayer.
Then I wrote this code:
public interface IAthlete
{
string GetName();
string GetSport();
}
public interface ITeam
{
void AddPlayer(IAthlete player);
IAthlete[] GetAthletes();
string GetName();
int GetNumberOfPlayers();
}
public class BasketballPlayer:IAthlete
{
private string name;
public string GetName()
{
return this.name;
}
public string GetSport()
{
return "Basketball";
}
public BasketballPlayer(string name)
{
this.name = name;
}
public void Run(int distance)
{
Console.WriteLine(this.name + " just ran " + distance.ToString() + " meters.");
}
public bool Shoot()
{
Console.WriteLine("Successful shot for " + this.name);
return true;
}
}
public class BasketballTeam: ITeam
{
BasketballPlayer[] players;
int numberOfPlayers;
private string name;
public void AddPlayer(BasketballPlayer player)
{
this.players[this.numberOfPlayers] = player;
this.numberOfPlayers++;
}
public IAthlete[] GetAthletes()
{
return this.players;
}
public string GetName()
{
return this.name;
}
public int GetNumberOfPlayers()
{
return this.numberOfPlayers;
}
public BasketballTeam(string name)
{
this.numberOfPlayers = 0;
this.name = name;
this.players = new BasketballPlayer[10];
}
}
class Program
{
static void Main(string[] args)
{
BasketballTeam bt = new BasketballTeam("MyTeam");
BasketballPlayer bp = new BasketballPlayer("Bob");
bt.AddPlayer(bp);
foreach (BasketballPlayer player in bt.GetAthletes())
{
Console.WriteLine(player.GetName());
}
foreach (IAthlete a in bt.GetAthletes())
{
Console.WriteLine(a.GetName());
}
}
}
But it won't compile because I'm using this:
public void AddPlayer(BasketballPlayer player)
in the BasketballPlayer instead of this
public void AddPlayer(IAthlete player)
I thought it should work because BasketballPlayer is an IAthlete.
And if I change it to IAthlete then I can make another class like this:
public class HockeyPlayer : IAthlete
{
private string name;
public string GetName()
{
return this.name;
}
public string GetSport()
{
return "Hockey";
}
public HockeyPlayer(string name)
{
this.name = name;
}
public void Run(int distance)
{
Console.WriteLine(this.name + " just ran " + distance.ToString() + " meters.");
}
}
and then do this in my main:
HockeyPlayer hp = new HockeyPlayer("Henry");
bt.AddPlayer(hp);
which is logically wrong because I'm adding HockeyPlayer to a BasketballTeam. Is it supposed to be like this and I should just be careful not to do that? What am I doing wrong? How do I show this using class diagrams? Does this lead to loose coupling?
You're trying to violate the Liskov Substitution Principle.
Anything that can be done with a supertype – such as adding a HockeyPlayer – can also be done with a subtype – including a BasketballTeam.
Instead, you should use generics:
class Team<TPlayer> where TPlayer : IAthlete {
public ReadOnlyCollection<TPlayer> Players { get; }
public string Name { get; }
public void AddPlayer(TPlayer player);
}
Here is some thoughts on your code. First, in C# you can use properties, instead of Get and Set methods.
public interface IAthlete
{
string Name { get; }
string Sport { get; }
}
With auto-properties you can ask compiler to generate back store for property. Also consider creating base class Player, which will hold implementation of Name and Sport properties.
public class Player : IAthlete
{
public Player(string name, string sport)
{
Name = name;
Sport = sport;
}
public string Name { get; private set; }
public string Sport { get; private set; }
}
Now when implementing some player, you can just pass values to base class constructor. And your custom players will hold only specific for them functionality (no code duplication). Also it's recommended to use string format, instead of concatenating strings:
public class BasketballPlayer : Player
{
public BasketballPlayer(string name)
: base(name, "Basketball")
{
}
public void Run(int distance)
{
Console.WriteLine("{0} just ran {1} meters.", Name, distance);
}
public bool Shoot()
{
Console.WriteLine("Successful shot for " + Name);
return true;
}
}
Now about teams. If you don't want to have FootballPlayers in your BasketballTeam, then you should create parametrized team. Also consider using IEnumerable:
public interface ITeam<TPlayer>
where TPlayer : IAthlete
{
void AddPlayer(TPlayer player);
IEnumerable<TPlayer> Players { get; }
string Name { get; }
int NumberOfPlayers { get; }
}
Again, for common functionality you can create base class. Keep in mind, that you should check how many players currently in your team before adding new player.
public class Team<TPlayer> : ITeam<TPlayer>
where TPlayer : IAthlete
{
private readonly List<TPlayer> _players = new List<TPlayer>();
public Team(string name, int teamSize)
{
Name = name;
TeamSize = teamSize;
}
public void AddPlayer(TPlayer player)
{
if (_players.Count == TeamSize)
throw new Exception("Players number exceeded");
_players.Add(player);
}
public string Name { get; private set; }
public int TeamSize { get; private set; }
public IEnumerable<TPlayer> Players
{
get { return _players; }
}
public int NumberOfPlayers
{
get { return _players.Count; }
}
}
And custom team implementation becomes really easy. You just tell which type of players it will have, and pass to base team implementation team name and size of team.
public class BasketballTeam : Team<BasketballPlayer>
{
public BasketballTeam(string name)
: base(name, 10)
{
}
}
Now your program works like a charm:
class Program
{
static void Main(string[] args)
{
BasketballTeam bt = new BasketballTeam("MyTeam");
BasketballPlayer bp = new BasketballPlayer("Bob");
bt.AddPlayer(bp);
foreach (BasketballPlayer player in bt.Players)
{
Console.WriteLine(player.Name);
}
foreach (IAthlete a in bt.Players)
{
Console.WriteLine(a.Name);
}
}
}
Logically ,
These should be your base classes : Team , Player
These should be your derived classes : BasketballTeam , BasketballPalyer
These should be interfaces on Player : IPlay() , IRun , IGetName etc.. whichever applicable
and so on...
Guideline : Verbs suits more good on interfaces and Noun suits good on classes. Noun in the requirement best suits for Class in the code.
SLaks is correct. You could add a generic constraint to your ITeam to not accept all players, but just those of one type:
public interface ITeam<T> where T : IAthlete
{
void AddPlayer(T player);
IAthlete[] GetAthletes();
// or: T[] GetAthletes();
string GetName();
int GetNumberOfPlayers();
}
A BasketballTeam implementation could look like:
public class BasketballTeam : ITeam<BasketballPlayer>
{
BasketballPlayer[] players;
// […]
public void AddPlayer(BasketballPlayer player)
{
this.players[this.numberOfPlayers] = player;
this.numberOfPlayers++;
}
public IAthlete[] GetAthletes()
{
return this.players;
}
// or:
// public BasketballPlayer[] GetAthletes()
// {
// return this.players;
// }
// […]
}
If your interfaces are meant to be used by variety of games, it seems that you are missing the Game here and perhaps need to use Generics:
public interface IGame
{
string Name {get;}
...
}
public class Bastketball : IGame
{
...
}
public interface ITeam<TGame> where TGame: class, IGame
{
void AddPlayer(IPlayr<TGame> player);
...
}
public interface IPlayer<TGame> where TGame: class, IGame
{
...
}
This will prevent from hockey player to be added to Basketball team.