Make C# logic layer calls generic - c#

I am looking for a way to make the examples I provided more generic if possible. Could anyone provide some guidance on the best way to do this?
I have over 10 classes that look identical except for the data type and the static manager calls that are used. Some of the static method calls to the managers may have different implementations. In the example I used Item1 and Item2 as examples.
// Item1
public static class Item1Extensions
{
public static void Save(this Item1 item)
{
try
{
if (!item.IsDirty) return;
Item1Manager.SaveItem(item);
}
catch (Exception ex)
{
throw new ItemSaveException();
}
}
public static Item1 Get(long id, long callerId)
{
Item1 item;
try
{
item = Item1Manager.GetItem(id, callerId);
}
catch (Exception ex)
{
throw new ItemRetrieveException();
}
return item;
}
public static List<Item1> List(long callerId)
{
return Item1Manager.GetItemsByCallerId(callerId).Where(x => x.IsActive).ToList();
}
public static bool Delete(long id, long callerId)
{
try
{
Item1Manager.DeactivateItem(id, callerId);
return true;
}
catch (Exception ex)
{
return false;
}
}
}
Item 2 is almost identical except maybe the manager calls
// Item2
public static class Item2Extensions
{
public static void Save(this Item2 item)
{
try
{
if (!item.IsDirty) return;
Item2Manager.SaveItem(item);
}
catch (Exception ex)
{
throw new ItemSaveException();
}
}
public static Item2 Get(long id, long callerId)
{
Item2 item;
try
{
item = Item2Manager.GetItem(id, callerId);
}
catch (Exception ex)
{
throw new ItemRetrieveException();
}
return item;
}
public static List<Item2> List(long callerId)
{
return Item2Manager.GetItemsByCallerId(callerId).Where(x => x.IsNotActive).ToList();
}
public static bool Delete(long id, long callerId)
{
try
{
Item2Manager.DeactivateItem(id, callerId);
return true;
}
catch (Exception ex)
{
return false;
}
}
}
I thought using some generics or a factory based pattern would be helpful but I could use some guidance. Since the structure of the logic layer classes look identical except for the manager calls it seems that the duplication of this logic can be simplified like
public static class Item2ManagerCalls
{
public static void Save(Item2 item)
{
Item2Manager.SaveItem(item);
}
public static Item2 Get(long id, long callerId)
{
return Item2Manager.GetItem(id, callerId);
}
public static List<Item2> List(long callerId)
{
return Item2Manager.GetItemsByCallerId(callerId).Where(x => x.IsActive).ToList();
}
public static bool Delete(long id, long callerId)
{
return Item2Manager.DeactivateItem(id, callerId);
}
}

Assuming that all item classes inherit from some base class names something like BaseItem that contains .IsDirty and .IsActive properties, then something like this should work:
// This is a fill for a class I assume that you already have
public class BaseItem
{
public bool IsDirty;
public bool IsActive;
}
// This is a fill for a class I assume that you already have
public class Item1 : BaseItem {}
// This is a fill for a class I assume that you already have
public class Item2 : BaseItem {}
// This is a fill for a class I assume that you already have
public class ItemSaveException : ApplicationException {}
// This is a fill for a class I assume that you already have
public class ItemRetrieveException : ApplicationException {}
// This is a fill for a class I assume that you already have
public static class Item1Manager
{
internal static void SaveItem(Item1 item) {}
internal static Item1 GetItem(long id, long callerId) { return new Item1(); }
internal static List<Item1> GetItemsByCallerId(long callerId) { return new List<Item1>(); }
internal static void DeactivateItem(long id, long callerId) {}
}
// This is a fill for a class I assume that you already have
public static class Item2Manager
{
internal static void SaveItem(Item2 item) {}
internal static Item2 GetItem(long id, long callerId) { return new Item2(); }
internal static List<Item2> GetItemsByCallerId(long callerId) { return new List<Item2>(); }
internal static void DeactivateItem(long id, long callerId) {}
}
public abstract class ItemManagerAdapter<TItemManagerAdapter, TItem>
where TItemManagerAdapter : ItemManagerAdapter<TItemManagerAdapter, TItem>, new()
where TItem : BaseItem
{
private static TItemManagerAdapter instance = new TItemManagerAdapter();
protected abstract void SaveItem(TItem item);
protected abstract TItem GetItem(long id, long callerId);
protected abstract List<TItem> GetItemsByCallerId(long callerId);
protected abstract void DeactivateItem(long id, long callerId);
public static void Save(TItem item)
{
try
{
if (!item.IsDirty) return;
instance.SaveItem(item);
}
catch (Exception ex)
{
throw new ItemSaveException();
}
}
public static TItem Get(long id, long callerId)
{
TItem item;
try
{
item = instance.GetItem(id, callerId);
}
catch (Exception ex)
{
throw new ItemRetrieveException();
}
return item;
}
public static List<TItem> List(long callerId)
{
return instance.GetItemsByCallerId(callerId).Where(x => x.IsActive).ToList();
}
public static bool Delete(long id, long callerId)
{
try
{
instance.DeactivateItem(id, callerId);
return true;
}
catch (Exception ex)
{
return false;
}
}
}
public class Item1ManagerAdapter : ItemManagerAdapter<Item1ManagerAdapter, Item1>
{
protected override void SaveItem(Item1 item) { Item1Manager.SaveItem(item); }
protected override Item1 GetItem(long id, long callerId) { return Item1Manager.GetItem(id, callerId); }
protected override List<Item1> GetItemsByCallerId(long callerId) { return Item1Manager.GetItemsByCallerId(callerId); }
protected override void DeactivateItem(long id, long callerId) { Item1Manager.DeactivateItem(id, callerId); }
}
public class Item2ManagerAdapter : ItemManagerAdapter<Item2ManagerAdapter, Item2>
{
protected override void SaveItem(Item2 item) { Item2Manager.SaveItem(item); }
protected override Item2 GetItem(long id, long callerId) { return Item2Manager.GetItem(id, callerId); }
protected override List<Item2> GetItemsByCallerId(long callerId) { return Item2Manager.GetItemsByCallerId(callerId); }
protected override void DeactivateItem(long id, long callerId) { Item2Manager.DeactivateItem(id, callerId); }
}
Use it like so:
public class Program
{
void Main()
{
var item1 = Item1ManagerAdapter.Get(1, 1);
Item1ManagerAdapter.Save(item1);
var item1Deleted = Item1ManagerAdapter.Delete(1, 1);
var item1s = Item1ManagerAdapter.List(1);
var item2 = Item2ManagerAdapter.Get(2, 2);
Item2ManagerAdapter.Save(item2);
var item2Deleted = Item2ManagerAdapter.Delete(2, 2);
var item2s = Item2ManagerAdapter.List(2);
}
}

Related

is this implementation of the Singleton and Object null Patterns Thread Safe?

Im trying to write a simple code to implement the Singleton and object null patterns.
the code should check if the new customer has a name, if yes put it in the real customer, and if not in the fakecustomer.
My focus in this question is: Is the Singleton pattern making my code thread safe in this case?
interface Icustomer
{
string Name { get; }
bool IsNull { get; }
}
class realcustomer : Icustomer
{
public string Name { get; set; }
public bool IsNull { get { return false; } }
public realcustomer(string name)
{
Name = name;
}
}
class fakecustomer : Icustomer
{
public string Name { get { return "customer not available"; } }
public bool IsNull { get { return true; } }
}
class checkifnull
{
public static Icustomer Getcustomer(string name)
{
if (string.IsNullOrEmpty(name))
{
return new fakecustomer();
}
else
{
return new realcustomer(name);
}
}
}
class Singleton
{
private int total = 0;
private static Icustomer cust;
private Singleton() { }
public static Icustomer makecust(string name)
{
if (cust == null)
{
if (string.IsNullOrEmpty(name))
{
cust = new fakecustomer();
}
else
{
cust = new realcustomer(name);
}
}
return cust;
}
public void add()
{
total++;
}
public int getTotal()
{
return total;
}
}
internal class Program
{
static void Main(string[] args)
{
Icustomer new_cust = Singleton.makecust("name");
}
}
each pattern works when implemented on its own, but now i'm trying to use both at the same time.

Drying up code with abstract class in C#

Let's say I have a warehouse with some "stuff" and I have some minions to run around this warehouse:
public class Warehouse {
public T GetItemInfo<T>(int id) where T : IItem, new() {}
public int AddItem<T>(T item) where T : IItem {}
public int RemoveItem<T>(int id) where T : IItem, new() {}
}
with minion interface:
public interface IMinion<T> where T : IItem {
T GetItemInfo(int id);
int AddItem<T>(T item);
int RemoveItem<T>(int id);
}
The PartMinion comes first:
public class PartMinion : IMinion<Part> {
protected Warehouse wh;
public PartMinion(Warehouse wh) {
this.wh = wh;
}
public Parts GetItemInfo(int id) {
return wh.GetItemInfo<Part>(id);
}
public int AddItem(int id) {
return wh.AddItem<Part>(id);
}
public int RemoveItem(int id) {
return wh.RemoveItem<Part>(id);
}
}
But, the FurnitureMinion is mostly the same as the PartMinion:
public class FurnitureMinion : IMinion<Furniture> {
protected Warehouse wh;
public FurnitureMinion(Warehouse wh) {
this.wh = wh;
}
public Furniture GetItemInfo(int id) {
return wh.GetItemInfo<Furniture>(id);
}
public int AddItem(int id) {
return wh.AddItem<Furniture>(id);
}
public int RemoveItem(int id) {
return wh.RemoveItem<Furniture>(id);
}
private IEnumerable<Parts> GetParts(int id) {
var query = "SELECT * FROM Parts " +
"JOIN FurnitureParts ON Parts.ID = FurnitureParts.PartID " +
"WHERE FurnitureParts.FurnitureID = ?";
var result = wh.Query<Parts>(query, id);
return result;
}
}
So I'd like to Abstract away the duplicate code between the two, but I can't quite get the syntax right:
public abstract class AbstractMinion : IMinion<T> {
protected Warehouse wh;
public AbstractMinion(Warehouse wh) {
this.wh = wh;
}
public Parts GetItemInfo(int id) {
return wh.GetItemInfo<T>(id);
}
public int AddItem(int id) {
return wh.AddItem<T>(id);
}
public int RemoveItem(int id) {
return wh.RemoveItem<T>(id);
}
}
Try adding a generic parameter to a class. You also need a where constraint, because this constraint exists on interface IMinion:
public abstract class AbstractMinion<T> : IMinion<T>
where T : IItem
{
protected Warehouse wh;
public AbstractMinion(Warehouse wh) {
this.wh = wh;
}
public T GetItemInfo(int id) {
return wh.GetItemInfo<T>(id);
}
public int AddItem(int id) {
return wh.AddItem<T>(id);
}
public int RemoveItem(int id) {
return wh.RemoveItem<T>(id);
}
}
So for PartMinion your class would look like this:
public class PartMinion : AbstractMinion<Part> {
public PartMinion(Warehouse wh) :base(wh){
}
}

Virtual function for printing generic linear linked list

I have an assignment to implement a linear linked list using generics in C# console application.
The class should also contain a print() method to print the elements of the list.
Conditions for Linear List are to be as a long type (CNodeLong) or String Type (CNodeString), both inherited from CNode with virtual function Print().
I have a problem implementing the printing method. I don't know where should it stand, and how to override it.
Here is my CNode class and CList class:
public class CNode<T>
{
private CNode<T> next;
private T item;
public CNode<T> Next
{
get { return next; }
set { next = value; }
}
public T Item
{
get { return item; }
set { item = value; }
}
public CNode(T item)
: this(item,null)
{
}
public CNode(T item, CNode<T> next)
{
this.item = item;
this.next = next;
}
}
class CList<T>
{
private CNode<T> first;
private CNode<T> last;
private int count;
public CNode<T> First
{
get { return first; }
}
public CNode<T> Last
{
get { return last; }
}
public int Count
{
get { return count; }
}
public CList(string strListName)
{
count = 0;
first = last = null;
}
}
You probably should override ToString method and add the virtual Print method to CNode.
(I've also added the PrintList method to CList):
public class CNode<T>
{
...
public override string ToString()
{
return item.ToString();
}
virtual public void Print()
{
Console.WriteLine(item);
}
}
class CList<T>
{
...
public void PrintList()
{
CNode<T> current = first;
while (current != null)
{
Console.WriteLine(current.ToString());
current = current.Next;
}
}
}
Then you can override the virtual method in the child classes:
public class CNodeString : CNode<string>
{
public CNodeString(string item) : base(item) { }
override public void Print()
{
Console.WriteLine("Printing from CNodeString");
base.Print();
}
}
public class CNodeLong : CNode<long>
{
public CNodeLong(long item) : base(item) { }
override public void Print()
{
Console.WriteLine("Printing from CNodeLong");
base.Print();
}
}

Is it possible to cast before passing to base constructor?

I'm trying to create an abstract generic manager which would give events for added/removed and provide abstract method for creating and finalizing an item.
Below is the code I've come up with, however in TestClass constructor passing TestManager for a ManagerBase argument to base produces compiler error for invalid cast even though TestManager is certainly a ManagerBase.
It is possible to make the Manager field an "object" and cast in at run time, but that'd be pretty ugly.
Is it possible to make it work, or perhaps I'm in the wrong direction?
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace ManagerTest
{
class Program
{
static void Main(string[] args)
{
var Manager = new TestManager();
Manager.ItemAdded += (manager, item) => Debug.WriteLine("Item added: " + item.Id);
Manager.ItemRemoved += (manager, item) => Debug.WriteLine("Item removed: " + item.Id);
var entity1 = Manager.Create("entity1");
var entity2 = Manager.Create("entity2");
Manager.Remove("entity1");
var entity3 = Manager.Create("entity3");
Manager.Remove("entity3");
Manager.Remove("entity4");
}
}
class TestClass : EntityBase, IDisposable
{
public TestClass(string id, TestManager manager) : base(id, manager) { Debug.WriteLine(Id + " - ctor"); }
public void Dispose() { Debug.WriteLine(Id + " - disposed"); }
}
class TestManager : ManagerBase<TestClass>
{
protected override TestClass CreateInternal(string key) { return new TestClass(key, this); }
protected override void FinalizeRemove(TestClass item) { item.Dispose(); }
}
abstract class EntityBase
{
public string Id { get; private set; }
public ManagerBase<EntityBase> Manager { get; private set; }
public EntityBase(string id, ManagerBase<EntityBase> manager)
{
this.Id = id;
this.Manager = manager;
}
}
abstract class ManagerBase<T> where T : EntityBase
{
public event Action<ManagerBase<T>, T> ItemAdded;
public event Action<ManagerBase<T>, T> ItemRemoved;
private readonly Dictionary<string, T> Storage = new Dictionary<string, T>();
protected abstract T CreateInternal(string key);
protected abstract void FinalizeRemove(T item);
public T Create(string key)
{
T newItem = null;
lock (Storage)
{
if (!Storage.ContainsKey(key))
{
newItem = CreateInternal(key);
Storage.Add(key, newItem);
ItemAdded.SafeInvoke(this, newItem);
}
}
return newItem;
}
public T Get(string key)
{
lock (Storage)
return Storage.ContainsKey(key) ? Storage[key] : null;
}
public bool Contains(string key)
{
lock (Storage)
return Storage.ContainsKey(key);
}
public bool Remove(string key)
{
bool returnValue = false;
lock (Storage)
if (Storage.ContainsKey(key))
{
var item = Storage[key];
returnValue = Storage.Remove(key);
ItemRemoved.SafeInvoke(this, item);
FinalizeRemove(item);
}
return returnValue;
}
}
static class Extensions
{
public static void SafeInvoke<T1, T2>(this Action<T1, T2> action, T1 arg1, T2 arg2)
{
var actionCopy = action;
if (actionCopy != null)
actionCopy(arg1, arg2);
}
}
}
The corrected code
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace ManagerTest
{
class Program
{
static void Main(string[] args)
{
var Manager = new TestManager();
Manager.ItemAdded += (manager, item) => Debug.WriteLine("Item added: " + item.Id);
Manager.ItemRemoved += (manager, item) => Debug.WriteLine("Item removed: " + item.Id);
var entity1 = Manager.Create("entity1");
var entity2 = Manager.Create("entity2");
Manager.Remove("entity1");
var entity3 = Manager.Create("entity3");
Manager.Remove("entity3");
Manager.Remove("entity4");
}
}
class TestClass : EntityBase, IDisposable
{
public TestClass(string id, TestManager manager) : base(id, manager) { Debug.WriteLine(Id + " - ctor"); }
public void Dispose() { Debug.WriteLine(Id + " - disposed"); }
}
class TestManager : ManagerBase<TestClass>, IManagerBase<TestClass>
{
protected override TestClass CreateInternal(string key) { return new TestClass(key, this); }
protected override void FinalizeRemove(TestClass item) { item.Dispose(); }
}
abstract class EntityBase
{
public string Id { get; private set; }
public IManagerBase<EntityBase> Manager { get; private set; }
public EntityBase(string id, IManagerBase<EntityBase> manager)
{
this.Id = id;
this.Manager = manager;
}
}
interface IManagerBase<out T>
where T : EntityBase
{
event Action<IManagerBase<T>, T> ItemAdded;
event Action<IManagerBase<T>, T> ItemRemoved;
T Create(string key);
T Get(string key);
bool Contains(string key);
bool Remove(string key);
}
abstract class ManagerBase<T> : IManagerBase<T> where T : EntityBase
{
public event Action<IManagerBase<T>, T> ItemAdded;
public event Action<IManagerBase<T>, T> ItemRemoved;
private readonly Dictionary<string, T> Storage = new Dictionary<string, T>();
protected abstract T CreateInternal(string key);
protected abstract void FinalizeRemove(T item);
public T Create(string key)
{
T newItem = null;
lock (Storage)
{
if (!Storage.ContainsKey(key))
{
Storage.Add(key, CreateInternal(key));
ItemAdded.SafeInvoke(this, newItem);
}
}
return newItem;
}
public T Get(string key)
{
lock (Storage)
return Storage.ContainsKey(key) ? Storage[key] : null;
}
public bool Contains(string key)
{
lock (Storage)
return Storage.ContainsKey(key);
}
public bool Remove(string key)
{
bool returnValue = false;
lock (Storage)
if (Storage.ContainsKey(key))
{
var item = Storage[key];
returnValue = Storage.Remove(key);
ItemRemoved.SafeInvoke(this, item);
FinalizeRemove(item);
}
return returnValue;
}
}
static class Extensions
{
public static void SafeInvoke<T1, T2>(this Action<T1, T2> action, T1 arg1, T2 arg2)
{
var actionCopy = action;
if (actionCopy != null)
actionCopy(arg1, arg2);
}
}
}
The problem is with the invariance of the T parameter in ManagerBase. You can't assign ManagerBase<Derived> to ManagerBase<Base>. You would be able to do that if the parameter was covariant, but this can be done inly in interfaces, not in classes. So maybe try to make the managerbase an interface? Like IManager<out T>
This article explains covariance/contravariance stuff quite well: http://tomasp.net/blog/variance-explained.aspx/

How to code a good Offline-Online Dispatcher

Let's assume that I have this scenario: I have got 2 repositories of information, and I want to access both, but it would be nice to leave the task of deciding which repo to use to common class.
The goal is to accomplish this with something similar to the code I've wrote below, but this sounds pretty bad:
where TOnline : class
where TOffline : class
where TContract : class
Sure I can ommit that, but bassically what I'm asking is what to do in order to stop using reflection and go typed. Maybe any design-pattern recomendation?
Code (if you copy/paste this on a console app replacing the Program class you should be able to run the example)
using CustomerDispatcher = DispatcherProxy<CustomerOnline, CustomerOffline, ICustomer>;
public interface ICustomer
{
string Get(int id);
}
public class CustomerOnline : ICustomer
{
public string Get(int id)
{
// Get From intranet DB
return "From DB";
}
}
public class CustomerOffline : ICustomer
{
public string Get(int id)
{
// Get From local storage
return "From local storage";
}
}
public class DispatcherProxy<TOnline, TOffline, TContract>
where TOnline : class
where TOffline : class
where TContract : class
{
public TContract Instance { get; set; }
public bool IsConnected { get; set; }
public DispatcherProxy()
{
// Asume that I check if it's connected or not
if (this.IsConnected)
this.Instance = (TContract)Activator.CreateInstance(typeof(TOnline));
else
this.Instance = (TContract)Activator.CreateInstance(typeof(TOffline));
}
}
class Program
{
static void Main(string[] args)
{
var customerDispatcher = new CustomerDispatcher();
Console.WriteLine("Result: " + customerDispatcher.Instance.Get(1));
Console.Read();
}
}
Thanks in advance!
You can add the new() constraint:
public class DispatcherProxy<TOnline, TOffline, TContract>
where TOnline : class, new()
where TOffline : class, new()
where TContract : class //isn't TContract an interface?
{
public TContract Instance { get; set; }
public bool IsConnected { get; set; }
public DispatcherProxy()
{
// Asume that I check if it's connected or not
if (this.IsConnected)
this.Instance = new TOnline() as TContract;
else
this.Instance = new TOffline() as TContract;
}
}
In case any of you are interested, I had to change the way I did this because it was checking connection at Constructor Level, and I needed that check at Operation Level.
using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
namespace ConsoleApplication1
{
public enum ConnectionStatus
{
Online,
Offline,
System // System checks connectivity
}
public static class Connectivity
{
private static ConnectionStatus ConnectionStatus = ConnectionStatus.Offline;
public static void ForceConnectionStatus(ConnectionStatus connectionStatus)
{
ConnectionStatus = connectionStatus;
}
public static bool IsConnected()
{
switch (ConnectionStatus)
{
case ConnectionStatus.Online:
return true;
case ConnectionStatus.Offline:
return false;
case ConnectionStatus.System:
return CheckConnection();
}
return false;
}
private static bool CheckConnection()
{
return true;
}
}
public class Unity
{
public static IUnityContainer Container;
public static void Initialize()
{
Container = new UnityContainer();
Container.AddNewExtension<Interception>();
Container.RegisterType<ILogger, OnlineLogger>();
Container.Configure<Interception>().SetInterceptorFor<ILogger>(new InterfaceInterceptor());
}
}
class Program
{
static void Main(string[] args)
{
Unity.Initialize();
var r = new Router<ILogger, OnlineLogger, OnlineLogger>();
Connectivity.ForceConnectionStatus(ConnectionStatus.Offline);
Console.WriteLine("Calling Online, will attend offline: ");
r.Logger.Write("Used offline.");
Connectivity.ForceConnectionStatus(ConnectionStatus.Online);
Console.WriteLine("Calling Online, will attend online: ");
r.Logger.Write("Used Online. Clap Clap Clap.");
Console.ReadKey();
}
}
public class Router<TContract, TOnline, TOffline>
where TOnline : TContract
where TOffline : TContract
{
public TContract Logger;
public Router()
{
Logger = Unity.Container.Resolve<TContract>();
}
}
public interface IOnline
{
IOffline Offline { get; set; }
}
public interface IOffline
{
}
public interface ILogger
{
[Test()]
void Write(string message);
}
public class OnlineLogger : ILogger, IOnline
{
public IOffline Offline { get; set; }
public OnlineLogger()
{
this.Offline = new OfflineLogger();
}
public void Write(string message)
{
Console.WriteLine("Online Logger: " + message);
}
}
public class OfflineLogger : ILogger, IOffline
{
public IOnline Online { get; set; }
public void Write(string message)
{
Console.WriteLine("Offline Logger: " + message);
}
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
public class TestAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new TestHandler();
}
}
public class TestHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
Console.WriteLine("It's been intercepted.");
if (!Connectivity.IsConnected() && input.Target is IOnline)
{
Console.WriteLine("It's been canceled.");
var offline = ((input.Target as IOnline).Offline);
if (offline == null)
throw new Exception("Online class did not initialized Offline Dispatcher.");
var offlineResult = input.MethodBase.Invoke(offline, this.GetObjects(input.Inputs));
return input.CreateMethodReturn(offlineResult, this.GetObjects(input.Inputs));
}
return getNext()(input, getNext);
}
private object[] GetObjects(IParameterCollection parameterCollection)
{
var parameters = new object[parameterCollection.Count];
int i = 0;
foreach (var parameter in parameterCollection)
{
parameters[i] = parameter;
i++;
}
return parameters;
}
}
}

Categories

Resources