I am trying to implement the Decorator pattern, but I keep getting an error when I try to compile my program. I cannot figure out why. I know it has something to with something not being an interface, but I have tried a bunch of changes and nothing is working. I appreciate any assistance!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OODAssignment3_ZackDavidson
{
class Program
{
static void Main(string[] args)
{
//Creates a new Calvin Klein Shirt fordecoration
CalvinKlein ckShirt = new CalvinKlein();
Console.WriteLine(Convert.ToString(ckShirt.GetBrand()));
//Puts a solid color on the Calvin Klein Shirt
solidColorDecorator ckSCD = new solidColorDecorator(ckShirt);
//Puts stripes on the Calvin Klein Shirt
stripedShirtDecorator ckSSD = new stripedShirtDecorator(ckShirt);
//Puts a pocket on the Clavin Klein Shirt
pocketShirtDecorator ckPSD = new pocketShirtDecorator(ckShirt);
//Creates a new Tommy Hilfiger Shirt
TommyHilfiger thShirt = new TommyHilfiger();
//Puts stripes on the Tommy Hilfiger Shirt
stripedShirtDecorator thSSD = new stripedShirtDecorator(thShirt);
//Puts a pocket on the Tommy Hilfiger Shirt
pocketShirtDecorator thPSD = new pocketShirtDecorator(thShirt);
}//EndOfMain
}//EndOfClassProgram
public abstract class ShirtsComponent
{
public abstract string GetBrand();
public abstract double GetPrice();
}
class CalvinKlein : ShirtsComponent
{
private string ck_Brand = "Calvin Klein";
private double ck_Price = 75.0;
public override string GetBrand()
{
return ck_Brand;
}
public override double GetPrice()
{
return ck_Price;
}
}
class TommyHilfiger : ShirtsComponent
{
private string th_Brand = "Tommy Hilfiger";
private double th_price = 85.0;
public override string GetBrand()
{
return th_Brand;
}
public override double GetPrice()
{
return th_price;
}
}
public abstract class Decorator : ShirtsComponent
{
ShirtsComponent fashion_Base = null;
protected string _brand = "Undefined Decorator";
protected double _price = 0.0;
protected Decorator(ShirtsComponent fashionBase)
{
fashion_Base = fashionBase;
}
#region ShirtsComponent Members
string ShirtsComponent.GetBrand()
{
return string.Format("{0}, {1}", fashion_Base.GetBrand(), _brand);
}
double ShirtsComponent.GetPrice()
{
return _price + fashion_Base.GetPrice();
}
#endregion
}
class solidColorDecorator : Decorator
{
public solidColorDecorator(ShirtsComponent fashionBase)
: base(fashionBase)
{
this._brand = "Solid Color Shirt";
this._price = 25.0;
}
}
class stripedShirtDecorator : Decorator
{
public stripedShirtDecorator(ShirtsComponent fashionBase)
: base(fashionBase)
{
this._brand = "Striped Shirt";
this._price = 50.0;
}
}
class pocketShirtDecorator : Decorator
{
public pocketShirtDecorator(ShirtsComponent fashionBase)
: base(fashionBase)
{
this._brand = "Dotted Shirt";
this._price = 90.0;
}
}
}//EndOfNamespace
This code is the problem:
#region ShirtsComponent Members
string ShirtsComponent.GetBrand()
{
return string.Format("{0}, {1}", fashion_Base.GetBrand(), _brand);
}
double ShirtsComponent.GetPrice()
{
return _price + fashion_Base.GetPrice();
}
#endregion
You don't need to specify the base class in the method declarations. This is the correct code:
#region ShirtsComponent Members
public override string GetBrand()
{
return string.Format("{0}, {1}", fashion_Base.GetBrand(), _brand);
}
public override double GetPrice()
{
return _price + fashion_Base.GetPrice();
}
#endregion
Related
I have the following setup:
public class Child<T>: BaseClass
{
public T Value;
}
public class IntChild: Child<int> { }
public class BoolChild: Child<bool> { }
public class FloatChild: Child<float> { }
public class MyProgram
{
public BaseClass Source;
public void SetValue(object val)
{
// I want to do something like the following
// ((Child) Source).Value = (val.GetType()) val;
// Instead, I have to do it like this
string temp = val.ToString();
switch (Source.GetType())
{
case "IntChild":
((IntChild) Source).Value = int.Parse(val.ToString());
break;
case "BoolChild":
((BoolChild) Source).Value = bool.Parse(val.ToString());
break;
case "FloatChild":
((FloatChild) Source).Value = float.Parse(val.ToString());
break;
}
}
}
I cannot modify the BaseClass (I could only overwrite ToString()).
How can I replace the switch with a simpler line of code? I want to do something like the following
((Child) Source).Value = (val.GetType()) val;
,instead of the switch. Is this even possible?
You should use the visitor pattern:
public abstract class BaseClassWithVisitor : BaseClass {
void AcceptVisitor(BaseClassVisitor visitor);
}
This means Child<T> become abstract too.
Make all Child<T> children class implements BaseClassWithVisitor.AcceptVisitor() method, so they are not abstract:
public class IntChild : Child<int> {
...
/// This method should be implemented in all Child<T> descendant classes
public override void AcceptVisitor(BaseClassVisitor visitor) { visitor.Visit(this); }
...
}
Then define the BaseClassVisitor interface :
public interface BaseClassVisitor {
void Visit(IntChild intChild);
void Visit(...); // all the other possible types
...
}
Then eventually create an implementation of the BaseClassVisitor that will do the operation you wanted:
public class SetValueVisitor : BaseClassVisitor {
void Visit(IntChild intChild) { intChild.Value = 1; }
void Visit(BoolChild boolChild) { boolChild.Value = false; }
...
}
Here is a complete example to make things clearer:
using System;
using System.Globalization;
namespace Visitor
{
class BaseClass
{
}
abstract class BaseClassWithVisitor : BaseClass
{
public abstract void AcceptVisitor(Visitor visitor);
}
abstract class Child<T> : BaseClassWithVisitor
{
public T Value;
}
class IntChild : Child<int>
{
public override void AcceptVisitor(Visitor visitor)
{
visitor.Visit(this);
}
}
class FloatChild : Child<float>
{
public override void AcceptVisitor(Visitor visitor)
{
visitor.Visit(this);
}
}
class StringChild : Child<string>
{
public override void AcceptVisitor(Visitor visitor)
{
visitor.Visit(this);
}
}
class Visitor
{
public object Value;
public void Visit(IntChild intChild)
{
intChild.Value = int.Parse(Value.ToString());
}
public void Visit(FloatChild floatChild)
{
floatChild.Value = float.Parse(Value.ToString(), CultureInfo.InvariantCulture);
}
public void Visit(StringChild stringChild)
{
stringChild.Value = Value.ToString();
}
}
class Program
{
static void Main(string[] args)
{
var visitor = new Visitor { Value = "12345" };
var intChild = new IntChild();
intChild.AcceptVisitor(visitor);
visitor = new Visitor { Value = "1.2345" };
var floatChild = new FloatChild();
floatChild.AcceptVisitor(visitor);
visitor = new Visitor { Value = "Hello World" };
var stringChild = new StringChild();
stringChild.AcceptVisitor(visitor);
Console.WriteLine("intChild.Value = {0}", intChild.Value);
Console.WriteLine("floatChild.Value = {0}", floatChild.Value);
Console.WriteLine("stringChild.Value = {0}", stringChild.Value);
}
}
}
This will output:
intChild.Value = 12345
floatChild.Value = 1,2345
stringChild.Value = Hello World
You can do it via reflection without classes modifying at all:
public void SetValue(object val)
{
Source.GetType().GetProperty("Value").SetValue(Source, value);
}
Small variation of answer already provided by Slava Utesinov
// Only set value if implementation of Child<>.
// If any other derived class of BaseClass with value field, then dont set
if(source.GetType().BaseType != null
&& source.GetType().BaseType.IsGenericType
&& source.GetType().BaseType.GetGenericTypeDefinition() == typeof(Child<>))
{
Console.WriteLine("Is implementation of Child<>");
source.GetType().GetField("Value").SetValue(source, val);
}
else
{
Console.WriteLine("Not implementation of Child<>");
}
One option to consider:
public void SetValue(object val)
{
dynamic dynamicSource = Source;
dynamicSource.Value = val;
}
It is a similar approach to the reflection based approaches, but a little more concise.
I'm new to C# and have no idea why doesn't it work. I'm trying to create 3 methods that create a new Vehicle object with different properties. I've tried to do it with polymorphism but it's been even worse. I bet the answer to that is so easy..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace PetrolStation
{
class Program
{
static void Main(string[] args)
{
Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed += new ElapsedEventHandler(DisplayTimeEvent);
aTimer.Interval = 1000; // 1000=1s
aTimer.Enabled = true;
Console.ReadLine();
void DisplayTimeEvent(object source, ElapsedEventArgs e)
{
Random rand = new Random();
int temp = rand.Next(1, 3);
if (temp == 2)
{
Vehicles vehicle = new Vehicles();
vehicle.newCar();
Console.Out.WriteLine("test", vehicle.carType); // it should print "car" after test but it doesn't
}
if (temp == 3)
{
Vehicles vehicle = new Vehicles();
vehicle.newVan();
Console.Out.WriteLine("test", vehicle.carType);// it should print "van" after test but it doesn't
}
}
}
}
Second class:
public class Vehicles
{
public string carType;
public string fuelType;
public int tankCap;
public double fuelInTank;
public Random rand = new Random();
public void newCar()
{
carType = "Car";
tankCap = 40;
fuelInTank = rand.NextDouble() * 10;
int tempFuelType = rand.Next(1, 3);
switch (tempFuelType)
{
case 1:
fuelType = "petrol";
break;
case 2:
fuelType = "Diesel";
break;
case 3:
fuelType = "LPG";
break;
}
}
public void newVan()
{
carType = "van";
tankCap = 80;
fuelInTank = rand.NextDouble() * 20;
int tempFuelType = rand.Next(1, 2);
if (tempFuelType == 1)
{
fuelType = "Diesel";
}
else
{
fuelType = "LPG";
}
}
using System;
namespace StackOverflow_OOP
{
class Program
{
// Randomness removed: you want a driver to **consistently** pass or fail.
static void Main(string[] args)
{
Car car = new Car(VehicleFuelType.Petrol, 20);
// The first arg specifies format/placement of the second
Console.Out.WriteLine("Vehicle Type: {0}", car.Type);
// In background, uses String.Format()
// See https://msdn.microsoft.com/en-us/library/system.string.format(v=vs.110).aspx
Van van = new Van(VehicleFuelType.Diesel, 40);
Console.Out.WriteLine("Vehicle Type: {0}", van.Type);
Console.ReadLine();
}
}
// A string that only takes a small number of values is called an enumeration
// See https://msdn.microsoft.com/en-us/library/sbbt4032.aspx
public enum VehicleFuelType
{
Petrol,
Diesel,
LPG
}
// Vehicle is clearly abstract in this context, while Car & Van are concrete.
// See explaination after code.
public abstract class Vehicle
{
public VehicleFuelType FuelType { get; }
public int TankCap { get; }
public double FuelInTank { get; private set; }
public string Type { get { return this.GetType().Name; } }
public Vehicle(VehicleFuelType fuelType, int tankCap, double fuelInTank)
{
FuelType = fuelType;
TankCap = tankCap;
FuelInTank = fuelInTank;
}
}
public class Car : Vehicle
{
public Car(VehicleFuelType fuelType, double fuelInTank) : base(fuelType, 40, fuelInTank)
{
}
}
public class Van : Vehicle
{
public Van(VehicleFuelType fuelType, double fuelInTank) : base(fuelType, 80, fuelInTank)
{
}
}
}
Classes: Abstract vs. Concrete
public abstract class Shape
{
public abstract double GetArea();
}
public class Circle : Shape
{
public int Radius { get; }
public Circle(int radius)
{
Radius = radius;
}
public override double GetArea()
{
return Math.PI * Radius * Radius;
}
}
public class Square : Shape
{
public int SideLength { get; }
public Square(int sideLength)
{
SideLength = sideLength;
}
public override double GetArea()
{
return SideLength * SideLength;
}
}
The simplest difference between an abstract class and a concrete one:
An abstract class cannot be instantiated (directly); a concrete one can.
For instance,
Shape shape = new Shape(); // impossible
Circle circle = new Circle(); // fine
Crucially,
Shape circle = new Circle(); // fine
Conceptually, it's impossible to create an abstract class (e.g. shape) without actually creating a concrete class (circle).
Even more simply, imagine going to a restaurant and telling the waiter you want "food". Obviously he can comply, but somewhere along the line "food" must become steak or tuna or spaghetti, etc.
Regarding the direct problem you mentioned:
The problem is related to the WriteLine call.
The signature of the call you mane
Console.Out.WriteLine("test", vehicle.carType);
is
public virtual void WriteLine(string format, object arg0)
So the first parameter in this call should have an item which you want to composite (see https://msdn.microsoft.com/en-us/library/system.string.format(v=vs.110).aspx for more details).
bottom line the call should be something like
Console.Out.WriteLine("test {0}", vehicle.carType);
Regarding the "polymorphism" you mentioned:
What you implemented isn't polymorphism.
You might want to read about polymorphism a little bit:
oop: https://msdn.microsoft.com/en-us/library/mt656686.aspx
polymorphism: https://msdn.microsoft.com/en-us/library/ms173152.aspx
I have a generic delegate like this:
public delegate T SomeHandler<T>(T input);
I have a generic class that take the delegate as a parameter to its constructor like this:
public class SomeClass<T>
{
private SomeHandler<T> m_handler;
public SomeClass(SomeHandler<T> handler)
{
m_handler = handler;
}
public void DoSomeStuff(T input)
{
T result = m_handler(input);
// some stuff
}
}
Most of the time I would instantiate the class with a default handler unless some special case is needed. So I have some default handlers for the types I use:
public static class DefaultHandlers
{
public static string DefaultStringHandler(string input)
{
return input;
}
}
In some cases, the type is instantiated with a special handler that is specific to its implementation:
public class Example
{
private SomeClass<string> m_typicalCase;
private SomeClass<string> m_specialCase;
public Example()
{
m_typicalCase = new SomeClass<string>(DefaultHandlers.DefaultStringHandler);
m_specialCase = new SomeClass<string>(SpecialHandler);
}
private string SpecialHandler(string input)
{
string result;
// Do something special
return result;
}
}
I want to create a default constructor for SomeClass that always instantiates the class with the same default handler for that type, but since the type is not know at compile time, I can't return the delegate that is the right type.
public class SomeClass<T>
{
...
public SomeClass()
{
m_handler = DefaultHandlers.GetDefaultHandler<T>();
}
...
}
Like this
public static class DefaultHandlers
{
public static SomeHandler<T> GetDefaultHandler<T>()
{
if (typeof(T) == typeof(string))
{
return DefaultStringHandler;
}
}
}
This does not work becuase DefaultStringHandler returns a string and the method expects T.
The only way that I have found to do this is the make a type-specific subclass of SomeClass that overloads the default constructor:
public class SomeStringClass : SomeClass<string>
{
public SomeStringClass()
: base(DefaultHandlers.DefaultStringHandler)
{
}
public SomeStringClass(SomeHandler<string> handler)
: base(handler)
{
}
}
It would be fun if generic types could have type-specific overloaded constructors that are used when instantiating the class of a specific type:
public class Foo<T>
{
public Foo<string>(string input)
{
}
public Foo<int>(int input)
{
}
public Foo(T input)
{
}
}
There must be a more elegant way to do with with a design pattern, Strategy maybe?
You could utilize dynamic to get something like SomeClass<string>():
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Zoltan
{
public class SomeClass<T>
{
private static readonly Func<T,T> FALL_BACK_HANDLER = a => a; //or what have you
private readonly Func<T,T> m_handler;
public SomeClass(Func<T,T> handler)
{
m_handler = handler;
}
public SomeClass()
{
m_handler = DefaultHandler.For<T>() ?? FALL_BACK_HANDLER;
}
public void DoSomeStuff(T input)
{
T result = m_handler(input);
Console.WriteLine(result);
}
}
public static class DefaultHandler
{
public static Func<T,T> For<T>()
{
return TypeAware<T>.Default;
}
private static class TypeAware<T>
{
private static readonly Func<T,T> DEFAULT;
static TypeAware()
{
var type = typeof(T);
if (type == typeof(string))
{
DEFAULT = a => DefaultHandler.StringHandler((dynamic) a);
}
else if (type == typeof(int))
{
DEFAULT = a => DefaultHandler.IntHandler((dynamic) a);
}
else
{
DEFAULT = null;
}
}
public static Func<T,T> Default { get { return DEFAULT; } }
}
public static string StringHandler(string a)
{
return a + " The default handler does some stuff!";
}
public static int IntHandler(int a)
{
return a + 2;
}
}
}
You would then consume SomeClass as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Zoltan
{
public class Program
{
public static void Main(string[] args)
{
var someStringObj = new SomeClass<string>();
someStringObj.DoSomeStuff("Hello World.");//prints "Hello World. The default handler does some stuff!"
var someIntObj = new SomeClass<int>();
someIntObj.DoSomeStuff(1);//prints 3
var someCustomDoubleObj = new SomeClass<double>(d => d - 2);
someCustomDoubleObj.DoSomeStuff(3);//prints 1
Console.Read();
}
}
}
Building on Jon Skeet and Alexei Levenkovs comments. From what I understand, something like this might be what you're after?
public delegate T SomeHandler<T>(T input);
public class SomeClass<T>
{
private SomeHandler<T> m_handler;
public SomeClass()
{
m_handler = (T input) => input;
}
public SomeClass(SomeHandler<T> handler)
{
m_handler = handler;
}
public void DoSomeStuff(T input)
{
T result = m_handler(input);
// some stuff
}
}
Another way would be to move the string-specific behaviour into a separate class and simply make an instance of that class if you want specific behaviour tied to a specific type
public delegate T SomeHandler<T>(T input);
public class SomeClass<T>
{
protected SomeHandler<T> m_handler;
protected SomeClass()
{
}
public SomeClass(SomeHandler<T> handler)
{
m_handler = handler;
}
public void DoSomeStuff(T input)
{
T result = m_handler(input);
// some stuff
}
}
public class SomeStringClass : SomeClass<string>
{
public SomeStringClass()
{
m_handler = DefaultStringHandler;
}
private string DefaultStringHandler(string input)
{
// Do default string stuff here...
return input;
}
public SomeStringClass(SomeHandler<string> handler):base(handler)
{
}
}
I have an interface
using ClassAbstractFactory;
public interface IPlugin
{
AbstractFactory GetFactory();
}
and an AbstractFactory
public abstract class AbstractFactory
{
public abstract AbstractCake CreateCake();
public abstract AbstractBox CreateBox();
}
public abstract class AbstractCake
{
public abstract void Interact(AbstractBox box);
}
public abstract class AbstractBox
{
}
and I have .dll that inherit AbstractCake
public class ChocolateCake : AbstractCake
{
private bool _isPacked;
private bool _isDecorated;
private string _nameOfCake;
public ChocolateCake()
{
_isPacked = false;
_isDecorated = false;
_nameOfCake = "Шоколадный";
}
public bool IsPacked
{
get { return _isPacked; }
}
public bool IsDecorated
{
get { return _isDecorated; }
}
public string NameOfCake { get; set; }
public override void Interact(AbstractBox box)
{
_isPacked = true;
}
}
I load dll like this:
public IPlugin LoadAssembly(string assemblyPath)
{
Assembly ptrAssembly = Assembly.LoadFile(assemblyPath);
foreach (Type item in ptrAssembly.GetTypes())
{
if (!item.IsClass) continue;
if (item.GetInterfaces().Contains(typeof(IPlugin)))
{
return (IPlugin)Activator.CreateInstance(item);
}
}
throw new Exception("Invalid DLL, Interface not found!");
}
List<IPlugin> list = new List<IPlugin>();
foreach (var assemblyPath in GetPathsListToDll())
{
list.Add(LoadAssembly(assemblyPath));
}
How can I acess to attributes in my ChocolateCake,to use them like
foreach (var str in list)
{
Boolean a = str.GetFactory().GetCake().CreateCake().IsPacked;
}
or like this
string a = str.GetFactory().GetCake().CreateCake().NameOfCake;
or like this
str.GetFactory().GetCake().CreateCake().NameOfCake("Something");
or like this
str.GetFactory().GetCake().CreateCake().IsDecorated(true);
The problem here is that the AbstractFactory has a method that returns AbstractCake, and AbstractCake itself has no properties at all. As it stands, you would need to downcast the Cake (direct, or with the as keyword) to a ChocolateCake prior to accessing any of its properties, which is really messy:
string a = (ChocolateCake)(str.GetFactory().CreateCake()).NameOfCake;
Here are some considerations:
Move the properties which are common to all types of cake into AbstractCake, e.g. NameOfCake, IsPacked and IsDecorated
Given that the AbstractFactory and AbstractCake classes do not have any implementation at all, consider changing these to interfaces instead of abstract classes, i.e. ICakeFactory and ICake. Concrete implementations will be ChocolateCakeFactory and ChocolateCake as before.
Consumers of the factory and the cake should now only access what is exposed on the interfaces (ICakeFactory, ICake and IBox), and not need to do any down casting or make any assumptions about the actual concrete type of Cake etc.
i.e.
public interface ICake
{
void Interact(IBox box);
bool IsPacked { get; }
bool IsDecorated { get; }
string NameOfCake { get; set; }
}
public class ChocolateCake : ICake
{
private bool _isPacked;
private bool _isDecorated;
private string _nameOfCake;
public ChocolateCake() // ctor is not on the interface and is implementation detail
{
_isPacked = false;
_isDecorated = false;
_nameOfCake = "Шоколадный";
}
public void Interact(IBox box) {...}
public bool IsPacked { get { return _isPacked; } }
public bool IsDecorated { get { return _isDecorated; } }
// ...
}
public interface ICakeFactory
{
ICake CreateCake();
IBox CreateBox();
}
public class ChocolateCakeFactory : ICakeFactory
{
public ICake CreateCake() {return new ChocolateCake();}
public IBox CreateBox() {return new ChocolateCakeBox();}
}
Re : Usage
It is highly unlikely that you would ever do this:
string a = str.GetFactory().GetCake().CreateCake().NameOfCake;
str.GetFactory().GetCake().CreateCake().NameOfCake = "Something"; // Prop setter
as this would create a new cake instance each time (and discard the instance). How about:
class Bakery
{
private readonly ICakeFactory _cakeFactory;
public Bakery(ICakeFactory cakeFactory)
{
Contract.Requires(cakeFactory != null);
cakeFactory = _cakeFactory;
}
bool BakeStuff()
{
var cake = _cakeFactory.CreateCake();
cake.NameOfCake = "StackOverflow";
return cake.IsDecorated && cake.IsPacked;
}
}
Edit, Re Raise change Events
This involves implementing INotifyPropertyChanged
public interface ICake : INotifyPropertyChanged
Which you can then raise on your mutable properties, e.g.
public string NameOfCake
{
get { return _nameOfCake} ;
set {
var propChanged = PropertyChanged;
if (propChanged != null && value != _nameOfCake)
{
propChanged(this, new PropertyChangedEventArgs("NameOfCake"));
}
_nameOfCake = value;
}
}
And subscribe like so
var cake = new ChocolateCake();
cake.PropertyChanged += (sender, eventArgs)
=> Console.WriteLine("Property {0} has changed", eventArgs.PropertyName);
Would this work?
public abstract class AbstractFactory
{
public abstract TCake CreateCake<TCake>() where TCake : AbstractCake, new();
public abstract AbstractBox CreateBox();
}
...
var cake = str.GetFactory().CreateCake<ChocolateCake>();
I don't know if I'm missing something here but isn't it strange that my code below always raises an exception on List.Contains part although I know for sure that list contain that element:
using System;
using System.Linq;
using System.Collections.Generic;
class SomeClass
{
public string param1 {get; private set;}
public string param2 {get; private set;}
private SomeClass(){}
public SomeClass(string param1, string param2)
{
this.param1 = param1;
this.param2 = param2;
}
}
class SomeClass2
{
private List<SomeClass> myList = new List<SomeClass>();
public void Add(SomeClass someclass)
{
myList.Add(someclass);
}
public void Remove(SomeClass someClass)
{
// this part always rises an exception
if(!myList.Contains(someClass))
throw new System.ArgumentException("some error");
else myList.Remove(someClass);
}
}
class MainClass
{
public static void Main (string[] args)
{
var _someClass = new SomeClass2();
_someClass.Add(new SomeClass("aaa", "bbb"));
try
{
_someClass.Remove(new SomeClass("aaa", "bbb"));
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
}
Quote from the documentation of the Contains method:
This method determines equality by using the default equality
comparer, as defined by the object's implementation of the
IEquatable(Of T).Equals method for T (the type of values in the list).
So you could implement IEquatable<T> on your objects if you want the Contains method to determine if 2 instances of SomeClass are equal:
class SomeClass: IEquatable<SomeClass>
{
public string param1 { get; private set; }
public string param2 { get; private set; }
private SomeClass() { }
public SomeClass(string param1, string param2)
{
this.param1 = param1;
this.param2 = param2;
}
public bool Equals(SomeClass other)
{
return param1 == other.param1 && param2 == other.param2;
}
}
Another possibility is to implement a custom EqualityComparer<T>:
class SomeClassEqualityComparer : IEqualityComparer<SomeClass>
{
private static readonly SomeClassEqualityComparer _instance = new SomeClassEqualityComparer();
public bool Equals(SomeClass x, SomeClass y)
{
return x.param1 == y.param1 && x.param2 == y.param2;
}
public int GetHashCode(SomeClass obj)
{
unchecked
{
int hash = 17;
hash = hash * 23 + obj.param1.GetHashCode();
hash = hash * 23 + obj.param2.GetHashCode();
return hash;
}
}
public static IEqualityComparer<SomeClass> Instance
{
get { return _instance; }
}
}
and then use the following overload of the Contains method:
if (!myList.Contains(someClass, SomeClassEqualityComparer.Instance))
throw new System.ArgumentException("some error");
You're not removing the same instance of SomeClass. This will work:
public static void Main ()
{
var _someClass = new SomeClass2();
var someClass = new SomeClass("aaa", "bbb");
_someClass.Add(someClass);
try
{
_someClass.Remove(someClass);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
To make your original code work you would need to implement IEquatable. See http://msdn.microsoft.com/en-us/library/bhkz42b3.aspx.
Sorry I didn't spend more time on the hash code implementation. I don't even remember if ^ is the right xor operator... I suppose I could rot13 before the xor, but that seemed kinda silly.
using System;
using System.Collections.Generic;
namespace DoesItCompile
{
class SomeClass
{
private object param1;
private object param2;
private SomeClass() { }
public SomeClass(string param1, string param2)
{
this.param1 = param1;
this.param2 = param2;
}
public override bool Equals(object oThat)
{
if (!(oThat is SomeClass))
return false;
SomeClass scThat = (SomeClass)oThat;
if (!string.Equals(this.param1, scThat.param1))
return false;
if (!string.Equals(this.param2, scThat.param2))
return false;
return true;
}
public override int GetHashCode()
{
return this.param1.GetHashCode() ^ this.param2.GetHashCode();
}
}
class SomeClass2
{
private List<SomeClass> myList = new List<SomeClass>();
public void Add(SomeClass someclass)
{
myList.Add(someclass);
}
public void Remove(SomeClass someClass)
{
// this part always rises an exception
if (!myList.Contains(someClass))
throw new System.ArgumentException("some error");
else myList.Remove(someClass);
}
}
class MainClass
{
public static void Main(string[] args)
{
var _someClass = new SomeClass2();
_someClass.Add(new SomeClass("aaa", "bbb"));
try
{
_someClass.Remove(new SomeClass("aaa", "bbb"));
Console.WriteLine("Have a nice president's day.");
}
catch (Exception e)
{
Console.WriteLine(e);
}
Console.ReadKey();
}
}
}
P.S. - I've no clue why you brought Zelda's stalker into the question, but I'm sure there's a good reason.