My brain is gonna to explode. :) So I would like to get help from you.
Please, think about my question like about just programmer puzzle. (Actually. perhaps it is very easy question for you, but not for me.)
It is needed to create array of objects. For example List where T is class. (I will describe Class T below). Also it is needed create “container” that will contain this array and some methods for work with this array. For example Add(), Remove(int IndexToRemove).
Class T must have field "Container", this way each elements of our array would be able to know where is it contained and has access its container's fields and methods. Notice, that in this case Class T should have type parameter. Indeed, it is not known beforehand which container's type is used.
Let us denote this class container as A and class element (class T) as AUnit.
Code:
class Program
{
static void Main(string[] args)
{
A a = new A();
a.Add();
a.Units[0].SomeField +=100;
Console.ReadKey();
}
}
class A
{
public List<AUnit> Units;
public A()//ctor
{
Units = new List<AUnit>();
}
public void Add()
{
this.Units.Add(new AUnit(this));
}
}
class AUnit
{
public int SomeField;
public A Container;
public string Name { get; private set; }
public AUnit(A container)
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
}
}
Public fields should be protected or private of course, but let think about this later.
You can ask “why we create public A Container field in AUnit”? We create field public string Name{get;private set;} (actually property but nevermind). And also we would like to be able to change value of this field for example method [Class AUnit] public bool Rename(string newName)();. The main idea of this method is changing Name field only that case if no one element in array (public List Units; ) has the same name like newName. But to achieve this, Rename method has to have access to all names that is currently used. And that is why we need Container field.
Code of extended version AUnit
class AUnit
{
public int SomeField;
public A Container;
public string Name { get; private set; }
public AUnit(A container)
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
}
public bool Rename(String newName)
{
Boolean res = true;
foreach (AUnit unt in this.Container.Units)
{
if (unt.Name == newName)
{
res = false;
break;
}
}
if (res) this.Name = String.Copy(newName);
return res;
}
}
Ok. If you still read it let's continue. Now we need to create Class B and class BUnit which will be very similar like Class A and Class Aunit. And finally the main question of this puzzle is HOW WE CAN DO IT? Of course, I can CopyPaste and bit modify A and AUnit and create this code.
class B
{
public List<BUnit> Units; //Only Type Changing
public B()//ctor Name changing...
{
Units = new List<BUnit>();//Only Type Changing
}
public void Add()
{
this.Units.Add(new BUnit(this));//Only Type Changing
}
}
class BUnit
{
public int SomeField;
public B Container;//Only Type Changing
public string Name { get; private set; }
public A a; //NEW FIELD IS ADDED (just one)
public BUnit(B container) //Ctor Name and arguments type changing
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
this.a=new A(); //New ROW (just one)
}
public bool Rename(String newName)
{
Boolean res = true;
foreach (BUnit unt in this.Container.Units) //Only Type Changing
{
if (unt.Name == newName)
{
res = false;
break;
}
}
if (res) this.Name = String.Copy(newName);
return res;
}
}
And I can to use this classes this way.
static void Main(string[] args)
{
B b = new B();
b.Add();
b.Units[0].a.Add();
b.Units[0].a.Units[0].SomeField += 100;
bool res= b.Units[0].a.Units[0].Rename("1");
res = b.Units[0].a.Units[0].Rename("1");
Console.ReadKey();
}
This construction is can be used to create “non-homogeneous trees”.
Help, I need somebody help, just no anybody…. [The Beatles]
I created B and BUnit using CopyPaste.
But how it can be done using “macro-definitions” or “Generic”, inherit or anything else in elegant style? (C# language)
I think that there is no reason to describe all my unsuccessful attempts and subquestions. Already topic is too long. : )
Thanks a lot if you still read it and understand what I would like to ask.
You need to implement a base type, lets call it UnitBase, with all common functionality. I'd structure your code the following way:
Create an interface for your container, this way you can change implementation to more performant solutions without modifying the elements you will be adding to the container.
public interface IContainer
{
Q Add<Q>() where Q : UnitBase, new();
IEnumerable<UnitBase> Units { get; }
}
Following the idea stated in 1, why not make the search logic belong to the container? It makes much more sense, as it will mostly depend on how the container is implemented:
public interface IContainer
{
Q Add<Q>() where Q : UnitBase, new();
IEnumerable<UnitBase> Units { get; }
bool Contains(string name);
}
A specific implementation of IContainer could be the following:
public class Container : IContainer
{
public Container()
{
list = new List<UnitBase>();
}
private List<UnitBase> list;
public Q Add<Q>() where Q: UnitBase, new()
{
var newItem = Activator.CreateInstance<Q>();
newItem.SetContainer(this);
list.Add(newItem);
return newItem;
}
public IEnumerable<UnitBase> Units => list.Select(i => i);
public bool Contains(string name) =>
Units.Any(unit => unit.Name == name);
}
Create a base class for your AUnit and BUnit types condensing all common functionality:
public abstract class UnitBase
{
protected UnitBase()
{
}
public IContainer Container { get; private set; }
public int SomeField;
public string Name { get; private set; }
public void SetContainer(IContainer container)
{
Container = container;
}
public bool Rename(String newName)
{
if (Container.Contains(newName))
return false;
this.Name = newName; //No need to use String.Copy
return true;
}
}
Implement your concrete types:
public class BUnit : UnitBase
{
public int SpecificBProperty { get; private set; }
public BUnit()
{
}
}
Shortcomings of this approach? Well, the container must be of type <UnitBase>, I've removed the generic type because it really wasn't doing much in this particular case as it would be invariant in the generic type.
Also, keep in mind that nothing in the type system avoids the following:
myContainer.Add<BUnit>();
myContainer.Add<AUnit>();
If having two different types in the same container is not an option then this whole set up kind of crumbles down. This issue was present in the previous solution too so its not something new, I simply forgot to point it out.
InBetween , I am very thankful to you for your advices. Actually I can't say that I understood your answer in full, but using your ideas I have done what I want.
Looks like my variant works well. However I would like to hear your (and everyone) opinions about code described below. The main goal of this structure is creating non-homogeneous trees. So could you estimate it from this side.
First of all. We need to create interfaces for both classes. We describe there all "cross-used" functions.
public interface IUnit<T>
{
string Name { get;}
void SetContainer(T t);
bool Rename(String newName);
}
public interface IContainer
{
bool IsNameBusy(String newName);
int Count { get; }
}
Next. Create Base for Unit Classes for future inheritance. We will use in this inheritors methods from Container Base so we need generic properties and IUnit interface.
class UnitBase<T> : IUnit<T> where T : IContainer
Unfortunately I don't know yet how to solve the problem with Constructor parameters. That is why I use method
SetContainer(T container).
Code:UnitBase
class UnitBase<T> : IUnit<T> where T : IContainer
{
protected T Container;
public string Name { get; private set; }
public UnitBase()
{
this.Name = "Default";
}
public void SetContainer(T container)
{
this.Container = container;
}
public bool Rename(String newName)
{
bool res = Container.IsNameBusy(newName);
if (!res) this.Name = String.Copy(newName);
return !res;
}
}
Next. Create ContainerBase
ContainerBase should:
1) has IContainer interface.
2)has information about what it will contain:
... where U : IUnit<C>, new()
3)and .... has information about what itself is. This information we need to pass as parameter to SetContainer() method.
Code ContainerBase:
class ContainerBase<U, C> : IContainer //U - Unit Class. C-Container Class
where U : IUnit<C>, new()
where C : ContainerBase<U, C>
{
protected List<U> Units;
public U this[int index] { get { return Units[index]; } }
public ContainerBase()//ctor
{
this.Units = new List<U>();
}
public void Add()
{
this.Units.Add(new U());
this.Units.Last().SetContainer(((C)this));//may be a bit strange but actualy this will have the same type as <C>
}
public bool IsNameBusy(String newName)
{
bool res = false;
foreach (var unt in this.Units)
{
if (unt.Name == newName)
{
res = true;
break;
}
}
return res;
}
public int Count { get { return this.Units.Count; } }
}
Cast ((TContainer)(this)) may be is a bit strange. But using ContainerBase we always should use NewInheritorContainer. So this cast is just do nothing…looks like...
Finally. This classes can be used like in this example.
class SheetContainer : ContainerBase<SheetUnit,SheetContainer> {public SheetContainer(){}}
class SheetUnit : UnitBase<SheetContainer>
{
public CellContainer Cells;
public PictureContainer Pictures;
public SheetUnit()
{
this.Cells = new CellContainer();
this.Pictures = new PictureContainer();
}
}
class CellContainer : ContainerBase<CellUnit, CellContainer> { public CellContainer() { } }
class CellUnit : UnitBase<CellContainer>
{
public string ValuePr;//Private Field
private const string ValuePrDefault = "Default";
public string Value//Property for Value
{
//All below are Just For Example.
get
{
return this.ValuePr;
}
set
{
if (String.IsNullOrEmpty(value))
{
this.ValuePr = ValuePrDefault;
}
else
{
this.ValuePr = String.Copy(value);
}
}
}
public CellUnit()
{
this.ValuePr = ValuePrDefault;
}
}
class PictureContainer : ContainerBase<PictureUnit, PictureContainer> { public PictureContainer() { } }
class PictureUnit : UnitBase<PictureContainer>
{
public int[,] Pixels{get;private set;}
public PictureUnit()
{
this.Pixels=new int[,]{{10,20,30},{11,12,13}};
}
public int GetSizeX()
{
return this.Pixels.GetLength(1);
}
public int GetSizeY()
{
return this.Pixels.GetLength(0);
}
public bool LoadFromFile(string path)
{
return false;
}
}
static void Main(string[] args)
{
SheetContainer Sheets = new SheetContainer();
Sheets.Add();
Sheets.Add();
Sheets.Add();
Sheets[0].Pictures.Add();
Sheets[1].Cells.Add();
Sheets[2].Pictures.Add();
Sheets[2].Cells.Add();
Sheets[2].Cells[0].Value = "FirstTest";
bool res= Sheets[0].Rename("First");//res=true
res=Sheets[2].Rename("First");//res =false
int res2 = Sheets.Count;
res2 = Sheets[2].Pictures[0].Pixels[1, 2];//13
res2 = Sheets[2].Pictures.Count;//1
res2 = Sheets[1].Pictures.Count;//0
res2 = Sheets[0].Pictures[0].GetSizeX();//3
Console.ReadKey();
}
Looks like it works like I want. But I didn’t test it full.
Let me say Thank you again, InBetween.
Related
I need some help with an example of Inheritance class (abstract). I can't use my function ToCSV() because i return a list of BananaPart and C# wants a list of FruitPart. How is it possible to solve this ?
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
FruitFactory fruitFactory = new FruitFactory();
Fruit myFruit = fruitFactory.Create("banana");
myFruit.FruitPart.ForEach(f => Console.WriteLine(f.ToString()));
}
}
public class FruitFactory {
public Fruit Create(string fruitType) {
switch(fruitType) {
case "banana":
return new Banana();
break;
default:
throw new Exception("undefined fruitType");
}
}
}
public abstract class Fruit {
protected string _name;
protected List<FruitPart> _fruitPart;
public Fruit() {
this._name = "A fruit";
}
public string Name { get { return this._name; } }
public List<FruitPart> FruitPart { get { return this._fruitPart; } }
}
public abstract class FruitPart { }
public class Banana : Fruit {
public Banana() : base() {
this._name = "banana";
this._fruitPart = ToCSV();
}
public List<BananaPart> ToCSV(){
return new List<BananaPart> { new BananaPart(5, "10"), new BananaPart(10, "20"), new BananaPart(20, "40") };
}
}
public class BananaPart : FruitPart {
private int _seed;
private string _dimensionPart;
public BananaPart (
int seed,
string dimensionPart
) {
this._seed = seed;
this._dimensionPart = dimensionPart;
}
}
It will be a pleasure for me to learn more about it ! Thank you in advance !
The reason that your code is not compiling is because List<T> is not covariant. In order to compile your code you need to change List<T> with IEnumerable<T> which has a covariant type parameter. So the changes are:
public abstract class Fruit {
protected string _name;
protected IEnumerable<FruitPart> _fruitPart;
public Fruit() {
this._name = "A fruit";
}
public string Name { get { return this._name; } }
public IEnumerable<FruitPart> FruitPart { get { return this._fruitPart; } }
}
You can learn more about covariance here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/
In short, covariance lets you deduce the assignment compatibility of two types based on the assignment compatibility of two other types. Since, we can assign a BananaPart to a FruitPart, we can deduce that a IEnumerable<BananaPart> can be assigned to IEnumerable<FruitPart>.
There is a problem in your model. Say I have a Banana, and it has a list of fruit-parts. Now I could call myBananana.FruitParts.Add(new ApplePart()), this cannot work since a banana is only composed of bananaparts.
To avoid this you need to be more restrictive in what you return. Instead of using a List<FruitPart> you could use IEnumerable<Fruitpart>. This avoids the problem since you cannot add anything to a IEnumerable.
If you are learning I would also recommend starting with interfaces instead of abstract classes. The later is sometimes called "Implementation inheritance", i.e. it is used to share code between two derived classes. This is sometimes useful, but in the majority of cases it is better to put this shared code in a third class, sometimes called "Composition over inheritance".
Your fruit could ook something like this using interfaces:
public interface IFruit
{
string Name { get; }
IEnumerable<IFruitPart> FruitPart { get; }
}
public class Banana : IFruit
{
public Banana() : base() => FruitPart = ToCSV();
public static List<BananaPart> ToCSV() => new List<BananaPart> { new BananaPart(5, "10"), new BananaPart(10, "20"), new BananaPart(20, "40") };
public string Name { get; } = "Banana";
public IEnumerable<IFruitPart> FruitPart { get; }
}
public interface IFruitPart { }
public class BananaPart : IFruitPart
{
public int Seed { get; }
public string DimensionPart { get; }
public BananaPart(int seed, string dimensionPart) => (Seed, DimensionPart) = (seed, dimensionPart);
}
Notice that you do not need much more code for the interface variant compared to the abstract class case.
You cannot safely cast List<Child> to List<Parent> because it would let you add Apple to List<Banana>.
You can create List<FuitPart> instead.
public List<FruitPart> ToCSV()
{
return new List<FruitPart> {
new BananaPart(5, "10"),
new BananaPart(10, "20"),
new BananaPart(20, "40") };
}
As List<BananaPart> doesn't inherite List<FruitPart> you can't do it like that.
I'll suggest you to make some wrapper classes, like FruitedDetails and BananaDetails that would inherite it. That way you could encapsulate the specific details of classes you are working with and wouldn't have to deal with various casting of objects when you pack your lists.
I have two constructors which feed values to readonly fields.
public class Sample
{
public Sample(string theIntAsString)
{
int i = int.Parse(theIntAsString);
_intField = i;
}
public Sample(int theInt) => _intField = theInt;
public int IntProperty => _intField;
private readonly int _intField;
}
One constructor receives the values directly, and the other does some calculation and obtains the values, then sets the fields.
Now here's the catch:
I don't want to duplicate the
setting code. In this case, just one
field is set but of course there may
well be more than one.
To make the fields readonly, I need
to set them from the constructor, so
I can't "extract" the shared code to
a utility function.
I don't know how to call one
constructor from another.
Any ideas?
Like this:
public Sample(string str) : this(int.Parse(str)) { }
If what you want can't be achieved satisfactorily without having the initialization in its own method (e.g. because you want to do too much before the initialization code, or wrap it in a try-finally, or whatever) you can have any or all constructors pass the readonly variables by reference to an initialization routine, which will then be able to manipulate them at will.
public class Sample
{
private readonly int _intField;
public int IntProperty => _intField;
private void setupStuff(ref int intField, int newValue) => intField = newValue;
public Sample(string theIntAsString)
{
int i = int.Parse(theIntAsString);
setupStuff(ref _intField,i);
}
public Sample(int theInt) => setupStuff(ref _intField, theInt);
}
Before the body of the constructor, use either:
: base (parameters)
: this (parameters)
Example:
public class People: User
{
public People (int EmpID) : base (EmpID)
{
// Add more statements here.
}
}
I am improving upon supercat's answer. I guess the following can also be done:
class Sample
{
private readonly int _intField;
public int IntProperty
{
get { return _intField; }
}
void setupStuff(ref int intField, int newValue)
{
//Do some stuff here based upon the necessary initialized variables.
intField = newValue;
}
public Sample(string theIntAsString, bool? doStuff = true)
{
//Initialization of some necessary variables.
//==========================================
int i = int.Parse(theIntAsString);
// ................
// .......................
//==========================================
if (!doStuff.HasValue || doStuff.Value == true)
setupStuff(ref _intField,i);
}
public Sample(int theInt): this(theInt, false) //"false" param to avoid setupStuff() being called two times
{
setupStuff(ref _intField, theInt);
}
}
Here is an example that calls another constructor, then checks on the property it has set.
public SomeClass(int i)
{
I = i;
}
public SomeClass(SomeOtherClass soc)
: this(soc.J)
{
if (I==0)
{
I = DoSomethingHere();
}
}
Yeah, you can call other method before of the call base or this!
public class MyException : Exception
{
public MyException(int number) : base(ConvertToString(number))
{
}
private static string ConvertToString(int number)
{
return number.toString()
}
}
Constructor chaining i.e you can use "Base" for Is a relationship and "This" you can use for same class, when you want call multiple Constructor in single call.
class BaseClass
{
public BaseClass():this(10)
{
}
public BaseClass(int val)
{
}
}
class Program
{
static void Main(string[] args)
{
new BaseClass();
ReadLine();
}
}
When you inherit a class from a base class, you can invoke the base class constructor by instantiating the derived class
class sample
{
public int x;
public sample(int value)
{
x = value;
}
}
class der : sample
{
public int a;
public int b;
public der(int value1,int value2) : base(50)
{
a = value1;
b = value2;
}
}
class run
{
public static void Main(string[] args)
{
der obj = new der(10,20);
System.Console.WriteLine(obj.x);
System.Console.WriteLine(obj.a);
System.Console.WriteLine(obj.b);
}
}
Output of the sample program is
50 10 20
You can also use this keyword to invoke a constructor from another constructor
class sample
{
public int x;
public sample(int value)
{
x = value;
}
public sample(sample obj) : this(obj.x)
{
}
}
class run
{
public static void Main(string[] args)
{
sample s = new sample(20);
sample ss = new sample(s);
System.Console.WriteLine(ss.x);
}
}
The output of this sample program is
20
Error handling and making your code reusable is key. I added string to int validation and it is possible to add other types if needed. Solving this problem with a more reusable solution could be this:
public class Sample
{
public Sample(object inputToInt)
{
_intField = objectToInt(inputToInt);
}
public int IntProperty => _intField;
private readonly int _intField;
}
public static int objectToInt(object inputToInt)
{
switch (inputToInt)
{
case int inputInt:
return inputInt;
break;
case string inputString:
if (!int.TryParse(inputString, out int parsedInt))
{
throw new InvalidParameterException($"The input {inputString} could not be parsed to int");
}
return parsedInt;
default:
throw new InvalidParameterException($"Constructor do not support {inputToInt.GetType().Name}");
break;
}
}
Please, please, and pretty please do not try this at home, or work, or anywhere really.
This is a way solve to a very very specific problem, and I hope you will not have that.
I'm posting this since it is technically an answer, and another perspective to look at it.
I repeat, do not use it under any condition. Code is to run with LINQPad.
void Main()
{
(new A(1)).Dump();
(new B(2, -1)).Dump();
var b2 = new B(2, -1);
b2.Increment();
b2.Dump();
}
class A
{
public readonly int I = 0;
public A(int i)
{
I = i;
}
}
class B: A
{
public int J;
public B(int i, int j): base(i)
{
J = j;
}
public B(int i, bool wtf): base(i)
{
}
public void Increment()
{
int i = I + 1;
var t = typeof(B).BaseType;
var ctor = t.GetConstructors().First();
ctor.Invoke(this, new object[] { i });
}
}
Since constructor is a method, you can call it with reflection. Now you either think with portals, or visualize a picture of a can of worms. sorry about this.
In my case, I had a main constructor that used an OracleDataReader as an argument, but I wanted to use different query to create the instance:
I had this code:
public Subscriber(OracleDataReader contractReader)
{
this.contract = Convert.ToString(contractReader["contract"]);
this.customerGroup = Convert.ToString(contractReader["customerGroup"]);
this.subGroup = Convert.ToString(contractReader["customerSubGroup"]);
this.pricingPlan= Convert.ToString(contractReader["pricingPlan"]);
this.items = new Dictionary<string, Member>();
this.status = 0;
}
So I created the following constructor:
public Subscriber(string contract, string customerGroup) : this(getSubReader(contract, customerGroup))
{ }
and this method:
private static OracleDataReader getSubReader(string contract, string customerGroup)
{
cmdSubscriber.Parameters[":contract"].Value = contract + "%";
cmdSubscriber.Parameters[":customerGroup"].Value = customerGroup+ "%";
return cmdSubscriber.ExecuteReader();
}
notes: a statically defined cmdSubscriber is defined elsewhere in the code; My main constructor has been simplified for this illustration.
In case you need to run something before calling another constructor not after.
public class Sample
{
static int preprocess(string theIntAsString)
{
return preprocess(int.Parse(theIntAsString));
}
static int preprocess(int theIntNeedRounding)
{
return theIntNeedRounding/100;
}
public Sample(string theIntAsString)
{
_intField = preprocess(theIntAsString)
}
public Sample(int theIntNeedRounding)
{
_intField = preprocess(theIntNeedRounding)
}
public int IntProperty => _intField;
private readonly int _intField;
}
And ValueTuple can be very helpful if you need to set more than one field.
NOTE: most of the solutions above does not work for structs.
Unfortunately initializing struct fields in a method called by a constructor is not recognized by the compiler and will lead to 2 errors:
in the constructor: Field xxxx must be fully assigned...
in the method, if you have readonly fields: a read-only field cannot be assigned except in a constructor.
These can be really frustrating for example when you just need to do simple check to decide on which constructor to orient your call to.
I have this weird behavior of AutoMapper. If I have a class that implements two interfaces were both of them are registered in CreateMap only one of them gets mapped and I do not understand why. It looks as if AutoMapper mapped only interface that is mentioned at first place in interfaces list.
Any thoughts? Please, checkout the following fiddler to see what the problem is.
Code from fiddler
A DTO to which I'd like to map:
class Dto {
public string StringValue {get;set;}
public int Value {get;set;}
}
Interfaces - sources from which I'd like to map:
interface ISourceA {
int Value {get;}
}
interface ISourceB {
string StringValue {get;}
}
...and two implementations for those. One that works, the other not really :/
class MultiSource: ISourceA, ISourceB {
private readonly string _s;
private readonly int _v;
public MultiSource(int v, string s) {
_v = v;
_s = s;
}
int ISourceA.Value { get { return _v; }}
string ISourceB.StringValue { get { return _s; }}
}
class StringSource: ISourceB {
public StringSource(string value) {
StringValue = value;
}
public string StringValue {get; private set;}
}
Here's how I use it:
public class Program
{
public static void Main()
{
Mapper.CreateMap<ISourceA, Dto>();
Mapper.CreateMap<ISourceB, Dto>();
var ms = new MultiSource(234, "woefjweofij");
var ss = new StringSource("iuahergiuw");
// This one is fine
Console.WriteLine(JsonConvert.SerializeObject(Mapper.Map<Dto>((ISourceA)ms)));
// This one is the same as that above. This is not what I intended to have in return :/
Console.WriteLine(JsonConvert.SerializeObject(Mapper.Map<Dto>((ISourceB)ms)));
// This works as expected
Console.WriteLine(JsonConvert.SerializeObject(Mapper.Map<Dto>(ss)));
}
}
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 need to refactor the following class:
public interface IEmployee
{
int VacationWeeks { get; }
int YearsWithCompany { set; get; }
double Salary { set; get; }
}
public class Employee : IEmployee
{
private readonly int vacationWeeks;
public Employee(int vacationWeeks)
{
this.vacationWeeks = vacationWeeks;
}
public int VacationWeeks
{
get { return vacationWeeks; }
}
public int YearsWithCompany { set; get; }
public double Salary { set; get; }
}
I need to make sure that VacationWeeks depends only on YearsWithCompany, and I am loading the mapping from the database. So far I have come up with this:
public class EmployeeNew : IEmployee
{
private Dictionary<int,int> vacationWeeksTable;
public EmployeeNew(Dictionary<int, int> vacationWeeksTable)
{
this.vacationWeeksTable = vacationWeeksTable;
}
public int VacationWeeks
{
get { return vacationWeeksTable[YearsWithCompany]; }
}
public int YearsWithCompany { set; get; }
public double Salary { set; get; }
}
This class implements what I want, but it still has one vulnerability: different instances of EmployeeNew in the same collection may have been created with different instances of vacationWeeksTable.
All instances of EmployeeNew in the same collection must refer to the same vacationWeeksTable.
The application I am refactoring uses lots of List all over the system, and we need to be able to modify YearsWithCompany and Salary, yet to guarantee that only one vacationWeeksTable is used per List. These lists are iterated several times; its elements are modified in each iteration.
Here is my imperfect solution. Suggestions are welcome:
// this class does two things, which I do not like
public class EmployeeList : IEnumerable<IEmployee>, IEmployee
{
private Dictionary<int, int> vacationWeeksTable;
private List<EmployeeSpecificData> employees;
private int currentIndex;
private EmployeeSpecificData CurrentEmployee
{
get { return employees[currentIndex]; }
}
public IEnumerator<IEmployee> GetEnumerator()
{
for (currentIndex = 0; currentIndex < employees.Count; currentIndex++)
{
yield return this;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public int VacationWeeks
{
get { return vacationWeeksTable[YearsWithCompany]; }
}
// this is ugly repetitive code I don't like
public int YearsWithCompany
{
get { return CurrentEmployee.YearsWithCompany; }
set { CurrentEmployee.YearsWithCompany = value; }
}
// this is ugly repetitive code I don't like
public double Salary
{
get { return CurrentEmployee.Salary; }
set { CurrentEmployee.Salary = value; }
}
}
I use the following to create and init some of the classes that need default and shared behaviour. Maybe if you can refactor it will help:
It is some form of the Factory and FlyWeight patterns combined (the flyweight part can be removed in your scenario), which in addition has a concept of class Type shared handlers.
I simplified and removed some stuff that you wont need but there is more to remove, I added comments.
Usage would be: (app init)
Dictionary<int,int> vacationWeeksTable = new Dictionary<int,int>();
// fill the table
Factory<Employee>.Init(vacationWeeksTable);
The whenever you create a Employee class:
// remove grouping in the factory class to remove this null
Employee em = Factory<Employee>.Create(null);
It takes only a WeakReference to the classes so you don't have to worry about GC.
Each employee will have the shared vacationWeeksTable setup on creation, without the possibility to change it after from outside if not using the factory class.
You could change the vacation table for all running instances of Employee at any moment in the runtime of the app with:
// this will call the method registered for SetInitialdata on all instances of Employee classes.
// again remove grouping to remove that null
Factory<Employee>.Call(EventHandlerTypes.SetInitialData, null, vacTable);
Sample implementation of Employee:
class Employee : IBaseClass
{
private Dictionary<int, int> vacationWeeksTable;
public virtual void RegisterSharedHandlers(int? group, Action<IKey, int?, EventHandlerTypes, Action<object, SharedEventArgs>> register)
{
group = 0; // disable different groups
register(new Key<Employee, int>(0), group, EventHandlerTypes.SetInitialData, SetVacationWeeksTable);
}
public virtual void RegisterSharedData(Action<IKey, object> regData)
{
// remove this from factory and interface, you probably dont need it
// I have been using it as a FlyWeight data store for classes.
}
private void SetVacationWeeksTable(object sender, SharedEventArgs e)
{
vacationWeeksTable = e.GetData<Dictionary<int, int>>();
}
}
Code pattern Implementation:
IBaseClass : interface that each of my classes that are creatable through a factory implement
public enum EventHandlerTypes
{
SetInitialData // you can add additional shared handlers here and Factory<C>.Call - it.
}
public class SharedEventArgs : EventArgs
{
private object data;
public SharedEventArgs(object data)
{
this.data = data;
}
public T GetData<T>()
{
return (T)data;
}
}
public interface IBaseClass
{
void RegisterSharedHandlers(int? group, Action<IKey, int?, EventHandlerTypes, Action<object, SharedEventArgs>> regEvent);
void RegisterSharedData(Action<IKey, object> regData);
}
Utility generic classes:
public interface IKey
{
Type GetKeyType();
V GetValue<V>();
}
public class Key<T, V> : IKey
{
public V ID { get; set; }
public Key(V id)
{
ID = id;
}
public Type GetKeyType()
{
return typeof(T);
}
public Tp GetValue<Tp>()
{
return (Tp)(object)ID;
}
}
public class Triple<T, V, Z>
{
public T First { get; set; }
public V Second { get; set; }
public Z Third { get; set; }
public Triple(T first, V second, Z third)
{
First = first;
Second = second;
Third = third;
}
}
Factory class with slight modification to handle your scenario:
public static class Factory<C> where C : IBaseClass, new()
{
private static object initialData;
private static Dictionary<IKey, Triple<EventHandlerTypes, int, WeakReference>> handlers = new Dictionary<IKey, Triple<EventHandlerTypes, int, WeakReference>>();
private static Dictionary<IKey, object> data = new Dictionary<IKey, object>();
static Factory()
{
C newClass = new C();
newClass.RegisterSharedData(registerSharedData);
}
public static void Init<IT>(IT initData)
{
initialData = initData;
}
public static Dt[] GetData<Dt>()
{
var dataList = from d in data where d.Key.GetKeyType() == typeof(Dt) select d.Value;
return dataList.Cast<Dt>().ToArray();
}
private static void registerSharedData(IKey key, object value)
{
data.Add(key, value);
}
public static C Create(int? group)
{
C newClass = new C();
newClass.RegisterSharedHandlers(group, registerSharedHandlers);
// this is a bit bad here since it will call it on all instances
// it would be better if you can call this from outside after creating all the classes
Factory<C>.Call(EventHandlerTypes.SetInitialData, null, initialData);
return newClass;
}
private static void registerSharedHandlers(IKey subscriber, int? group, EventHandlerTypes type, Action<object, SharedEventArgs> handler)
{
handlers.Add(subscriber, new Triple<EventHandlerTypes, int, WeakReference>(type, group ?? -1, new WeakReference(handler)));
}
public static void Call<N>(EventHandlerTypes type, int? group, N data)
{
Call<N>(null, type, group, data);
}
public static void Call<N>(object sender, EventHandlerTypes type, int? group, N data)
{
lock (handlers)
{
var invalid = from h in handlers where h.Value.Third.Target == null select h.Key;
// delete expired references
foreach (var inv in invalid.ToList()) handlers.Remove(inv);
var events = from h in handlers where h.Value.First == type && (!#group.HasValue || h.Value.Second == (int)#group) select h.Value.Third;
foreach (var ev in events.ToList())
{
// call the handler
((Action<object, SharedEventArgs>)ev.Target)(sender, arg);
}
}
}
}
Make a class which contains a Dictionary. Creating or getting instance of this new class will load the dictionary in a consistent way. Then your BOs can take an instance of the class, thus ensuring they're all using the same data (because the class containingthe list knows how to load itself with the proper set of data).