Any way to avoid Object/casts in the child classes here? - c#

Following the book "Artificial Intelligence - A Modern Approach" I am trying to make search algorithm implementations (DFS, A*, etc.) that can work with different problems (path from A to B, sliding-block puzzle, etc.) instead of just the one specific problem.
public abstract class Problem
{
protected Problem(object initialState)
{
InitialState = initialState;
}
public object InitialState { get; }
/// <summary>
/// Checks if the state is the goal state
/// </summary>
public abstract bool IsGoalState(object state);
/// <summary>
/// Returns the actions available from the state
/// </summary>
public abstract ISet<Action> Actions(object state);
/// <summary>
/// Returns the state that results after performing the action on the state
/// </summary>
public abstract object ResultState(object state, Action action);
/// <summary>
/// Returns the cost of action to reach from state to reachedState
/// </summary>
/// <param name="state">The state from which the action will be performed</param>
/// <param name="action">One of the actions available in the state</param>
/// <param name="reachedState">The state that results after performing the action</param>
public virtual int StepCost(object state, Action action, object reachedState)
{
return 1;
}
}
_
public class Node
{
public Node(object state)
{
State = state;
PathCost = 0;
}
/// <summary>
/// </summary>
/// <param name="action">The action that was applied to the parent to generate the node</param>
/// <param name="stepCost">The cost from the parent node to this node</param>
public Node(object state, Node parent, Action action, int stepCost)
: this(state)
{
Parent = parent;
Action = action;
if (Parent != null)
PathCost = Parent.PathCost + stepCost;
}
public object State { get; }
public Node Parent { get; }
/// <summary>
/// The action that was applied to the parent to generate the node
/// </summary>
public Action Action { get; }
/// <summary>
/// The cost of the path from the initial statee to the node
/// </summary>
public int PathCost { get; }
public bool IsRootNode => Parent == null;
public IEnumerable<Node> PathFromRoot()
{
var path = new Stack<Node>();
var node = this;
while (!node.IsRootNode)
{
path.Push(node);
node = node.Parent;
}
path.Push(node); // root
return path;
}
}
_
public abstract class Action
{
/// <summary>
/// true if it is a "No Operation" action
/// </summary>
public virtual bool IsNoOp()
{
return false;
}
public string Name => GetType().Name;
public override string ToString()
{
return Name;
}
}
public class NoOp : Action
{
public override bool IsNoOp()
{
return true;
}
}
public abstract class EightPuzzleAction : Action
{
}
/// <summary>
/// Move the blank tile to the left
/// </summary>
public class MoveLeft : EightPuzzleAction
{
}
// the same MoveRight, MoveTop, MoveBottom
In order to do that I can implement methods from this base Problem class and pass that concrete instance to a search algorithm (that accepts Problem).
class EightPuzzleProblem : Problem
{
private readonly int[,] _goalState =
{
{0, 1, 2},
{3, 4, 5},
{6, 7, 8},
};
public EightPuzzleProblem(int[,] initialState) : base(initialState)
{ }
public override bool IsGoalState(object state)
{
var puzzleState = (int[,]) state;
......... <check if puzzleState is the same as _goalState>
}
............
}
class DepthFirstSearch
{
public IEnumerable<Action> Search(Problem p)
{
return DfsRecursive(p, new Node(p.InitialState));
}
public IEnumerable<Action> DfsRecursive(Problem p, Node node)
{
if (p.IsGoalState(node.State))
return node.PathFromRoot();
.......<simple DFS implementation>
}
}
// usage example
var dfs = new DepthFirstSearch();
var result = dfs.Search(new EightPuzzleProblem(initialState));
if (!result.Any)
// fail
if (result.Count == 1 && result[0].IsNoOp)
// already at goal
foreach (var act in result)
{
if (act is MoveLeft) .....
}
But I see one inconvenience with my class design: in the concrete class implementation code I need to have a lot of casts from object. Is there any way to avoid that?
If I make the Problem class generic and inherit ConcreteProblem from Problem<Something> then I will not be able to use it via Problem...

Why don't you inject your GoalState too and make GameState also pluggable using the interface like below. In this way you can implement any operation you want to do on two States in the concrete class and Problem class just needs to call those functions. Also you can have different types of states too.
public abstract class Problem<T> where T:IGameState
{
protected Problem(T initialState)
{
InitialState = initialState;
}
public T InitialState { get; set; }
/// <summary>
/// Checks if the state is the goal state
/// </summary>
public abstract bool IsGoalState(T state);
}
public class EightPuzzleProblem<T> : Problem<T> where T : IGameState
{
private readonly T _goalState;
public EightPuzzleProblem(T initialState, T goalState)
: base(initialState)
{
_goalState = goalState;
}
public override bool IsGoalState(T state)
{
return _goalState.IsEqual(state);
}
}
public interface IGameState
{
bool IsEqual(IGameState state);
}
public class EightPuzzleGameState : IGameState
{
private readonly int[,] _goalState =
{
{0, 1, 2},
{3, 4, 5},
{6, 7, 8},
};
public bool IsEqual(IGameState state)
{
//Compare state with _goalState
}
}

You could actually make Problem generic with the generic param set to the actual state.
public abstract class Problem<T> where T : IState{
public abstract bool IsGoalState(T state);
}
Within your derived classes you can now simply derive from Problem passing the actual type of IState as generic parameter:
class MyDerived : Problem<MyState> {
public override bool IsGoalState(MyState state) { ... }
}

Related

Instantiate generic repository dynamically and how to add entity base class to Entity Framework

Following is the implementation of repository pattern using EF6. I want to use the generic repository in the following way thereby removing the need to create repository for every type
_unitOfWork.Repository(entityName).Insert(entityName)
public interface IRepository<T> where T : class
{
//--Search Operations
IEnumerable<T> Get();
T GetByID(object id);
void Insert(T entity);
void Delete(object id);
void Delete(T entityToDelete);
void Update(T entityToUpdate);
}
I have created a base class that all entities will inherit. The intent of this bases class is so that i can refer all entities with this base class.
public class IRepositoryEntity
{
}
Following is the Entity Framework generated code, I have inherited this entity from IRepositoryEntity
public partial class Client_Entity: IRepositoryEntity
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Client_Entity()
{
}
public int Id { get; set; }
}
Following is the generic repository
public class GenericRepository<IRepositoryEntity> : IRepository<IRepositoryEntity> where IRepositoryEntity : class
{
#region Private member variables...
internal ConsularDB_March2016Entities Context;
internal DbSet<IRepositoryEntity> DbSet;
#endregion
#region Public Constructor...
/// <summary>
/// Public Constructor,initializes privately declared local variables.
/// </summary>
/// <param name="context"></param>
public GenericRepository(ConsularDB_March2016Entities context)
{
this.Context = context;
this.DbSet = context.Set<IRepositoryEntity>();
}
///// <summary>
///// Public Constructor,initializes privately declared local variables.
///// </summary>
///// <param name="context"></param>
//public GenericRepository()
//{
// this.Context = context;
// this.DbSet = context.Set<IRepositoryEntity>();
//}
#endregion
#region Public member methods...
/// <summary>
/// generic Get method for Entities
/// </summary>
/// <returns></returns>
public IEnumerable<IRepositoryEntity> Get()
{
IQueryable<IRepositoryEntity> query = DbSet;
return query.ToList();
}
}
Following is the IUnitOfWork interface and its implementation
public interface IUnitOfWork
{
#region Properties
GenericRepository<Client_Entity> ClientRepository { get; }
#endregion
#region Public methods
/// <summary>
/// Save method.
/// </summary>
void Save();
GenericRepository<IRepositoryEntity> Repository(IRepositoryEntity entity);
#endregion
}
/// <summary>
/// Unit of Work class responsible for DB transactions
/// </summary>
public class UnitOfWork : IDisposable, IUnitOfWork
{
#region Private member variables...
private March2016Entities _context = null;
private GenericRepository<Client_Entity> _clientRepository;
#endregion
public UnitOfWork()
{
_context = new March2016Entities();
}
#region Public member methods...
/// <summary>
/// Save method.
/// </summary>
public void Save()
{
try
{
_context.Configuration.ValidateOnSaveEnabled = false;
_context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
var context = ((IObjectContextAdapter)_context).ObjectContext;
var refreshobjects = _context.ChangeTracker.Entries().Select(c => c.Entity).ToList();
context.Refresh(System.Data.Entity.Core.Objects.RefreshMode.StoreWins, refreshobjects);
_context.SaveChanges();
}
catch (DbEntityValidationException e)
{
var outputLines = new List<string>();
foreach (var eve in e.EntityValidationErrors)
{
outputLines.Add(string.Format("{0}: Entity of type \"{1}\" in state \"{2}\" has the following validation errors:", DateTime.Now, eve.Entry.Entity.GetType().Name, eve.Entry.State));
foreach (var ve in eve.ValidationErrors)
{
outputLines.Add(string.Format("- Property: \"{0}\", Error: \"{1}\"", ve.PropertyName, ve.ErrorMessage));
}
}
System.IO.File.AppendAllLines(#"C:\errors.txt", outputLines);
throw e;
}
}
#endregion
#region Implementing IDiosposable...
#region private dispose variable declaration...
private bool disposed = false;
#endregion
/// <summary>
/// Protected Virtual Dispose method
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
Debug.WriteLine("UnitOfWork is being disposed");
_context.Dispose();
}
}
this.disposed = true;
}
/// <summary>
/// Dispose method
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
#region GenericMembers
Dictionary<string, GenericRepository<IRepositoryEntity>> repostories = new Dictionary<string, GenericRepository<IRepositoryEntity>>();
/// <summary>
/// Generic Repository method which checks the repository is available if not,
/// it sets it up.
/// </summary>
/// <param name="entity">Entity</param>
/// <returns>Repository to use.</returns>
public GenericRepository<IRepositoryEntity> Repository(IRepositoryEntity entity)
{
string index = entity.GetType().ToString();
if (!repostories.ContainsKey(index))
{
//Reflections to create the repoositiory if it is not needed.
Type type1 = typeof(GenericRepository<IRepositoryEntity>);
Type[] typeArgs = { entity.GetType() };
Type constructed = type1.MakeGenericType(typeArgs);
object o = Activator.CreateInstance(constructed, this._context);
//if (o is GenericRepository<IRepositoryEntity>)
//{
object genericRepo = (object)o;
var rep = (GenericRepository<IRepositoryEntity>)genericRepo;
//rep.Context = this._context;
repostories.Add(index, rep);
//}
}
return this.repostories[index];
}
#endregion
}
I am trying to create a list of GenericRepository dynamically in the following function
public GenericRepository<IRepositoryEntity> Repository(IRepositoryEntity entity)
while creating the instance, it is throwing the following exception
An exception of type 'System.InvalidOperationException' occurred in mscorlib.dll but was not handled in user code
Additional information: GenericRepository`1[IRepositoryEntity] is not a GenericTypeDefinition. MakeGenericType may only be called on a type for which Type.IsGenericTypeDefinition is true.
I understand the exception, however not sure on how can I change the implementation so that i am able to achieve the desired functionality. Also how can I add IRepositoryEntity to EF model because it says it is not part of the model.
public void ValidateGenericEntityInsert(IRepositoryEntity entityName)
{
IRepositoryEntity entity = (IRepositoryEntity)Activator.CreateInstance(entityName);
_unitOfWork.Repository(entityName).Insert(entityName);
// int generatedId = GetPropertyFromEntity(entity, en => en.Id);
int generatedId = (int)GetPropertyFromEntity(entityName, "Id");
Assert.That(generatedId, Is.GreaterThan(0));
}

C# Polymorphism with Dictionaries not working as intended

I've have a a abstract Base class
public abstract class absTerminalStrategy
{
//....
}
and two child class lets call them Class A and Class B
Class A
{
//Some Params
public A (/*Some Params*/)
}
Class B
{
//Some Params
Public B (/*Some Params*/)
}
in "upper" layer class I'll call Class Control
I've those objects
{
//..
public static absTerminalStrategy terminal = null;
/// <summary>
/// stores all instencese of A_tarategy to be used --> string A_IP
/// </summary>
public static Dictionary<string, A> terminal_A_Dictionary = new Dictionary<string, A_Strategy>();
/// <summary>
/// stores all instencese of B_Scritping to be used --> string B_Port
/// </summary>
public static Dictionary<string, B> terminal_B_Dictionary = new Dictionary<string, B_trategy>();
//..
}
Now in run time I add some instances to the dictionaries and later I need to "jump" between
various instances using this method
public static bool Terminalset(string terminalName)
{
string InterfaceType = terminalName.Split(':')[0];//cutting the root name for switch
switch(InterfaceType)
{
case "A":
{
A New_A =null;
if (terminal_A_Dictionary.TryGetValue(terminalName, out New_A))//return bool
terminal = New_A;
else return false;
}
break;
case "B":
{
B New_B =null;
if (terminal_B_Dictionary.TryGetValue(terminalName, out New_B))//return bool
terminal = New_B;
else return false;
}
break;
}
return true;
}
My problem is , when I change between class A to class B everything works fine
when I change between instances of class A using the dictionary it seems to work fine
But when I do the same with Class B I doesn't work and stays on it last property to entered to he dictionary (the last new instance to entered)
what can be the problem ?
Also this is how add to the dictionary
public static bool TermialCheckCreate (TerminalType terminalType , GlobalParam.A a = null , GlobalParam.B b= null)
{
switch (terminalType)
{
case TerminalType.A:
{
if (terminal_A_Dictionary.ContainsKey(string.Format("A:{0}", _A_Param.AIp))) break;
if (a == null) return false;
A_Strategy terminal = new A_Strategy(_A_Param.AIp, GlobalParam.A_PORT, 60);
terminalTelnetDictionary.Add(string.Format("A:{0}",_A_Param.AIp), terminal);
}
break;
case TerminalType.B:
{
if (terminal_B_Dictionary.ContainsKey(string.Format("B:{0}", _B_Param.Bcom))) break;
if (b == null) return false;
B_strategy terminal = new B_Strategy(GlobalParam.AppDirectory, _B_Param.BCom, _B_Param.BRate);
terminal_B_Dictionary.Add(string.Format("B:{0}",_B_Param.BCom), terminal);
}
break;
}
return true;
}
EDIT small corrections
copy of the classes involved
class to control all the dictionaries
public enum TerminalType {serial , Telent };
public static class TerminalControl
{
/// <summary>
/// stores all instencese of TelnetStarategy to be used --> string telnetIP
/// </summary>
public static Dictionary<string, TelnetStrategy> terminalTelnetDictionary = new Dictionary<string, TelnetStrategy>();
/// <summary>
/// stores all instencese of SerialScritping to be used --> string SerailPort
/// </summary>
public static Dictionary<string, SerialStrategy> terminalSerialDictionary = new Dictionary<string, SerialStrategy>();
/// <summary>
/// abstract instance , chooses between serial and telent
/// </summary>
public static absTerminalStrategy terminal = null;
/// <summary>
/// static constructor
/// </summary>
static TerminalControl()
{
}
/// <summary>
/// Inherits from serial/telnet strategy will run this class of commands
/// </summary>
/// <param name="terminalType"></param>
/// <param name="TelnetIP"></param>
/// <param name="SerialPort"></param>
/// <param name="SerialBaudRate"></param>
/// <param name="Command"></param>
/// <returns></returns>
public static List<string> TerminalSendAndWaitForList(string Command,string terminalName,string fullpathLog="")
{
if (!Terminalset(terminalName)) return new List<string>(new string[] { "ERROR : Device Not Found !!! Check it and add" });
return terminal.SendAndWaitForList(Command);
}
public static bool Terminalset(string terminalName)
{
string InterfaceType = terminalName.Split(':')[0];
switch(InterfaceType)
{
case "Telnet":
{
TelnetStrategy NewTelnet =null;
terminal = NewTelnet;
if (terminalTelnetDictionary.TryGetValue(terminalName, out NewTelnet))//return bool
terminal = NewTelnet;
else return false;
}
break;
case "Serial":
{
SerialStrategy NewSerial =null;
terminal = NewSerial;
if (terminalSerialDictionary.TryGetValue(terminalName, out NewSerial))//return bool
terminal = NewSerial;
else return false;
}
break;
}
return true;
}
/// <summary>
/// added new terminal to inner dictionary
/// </summary>
/// <param name="terminalType"></param>
/// <param name="telentParam"></param>
/// <param name="serialParam"></param>
/// <returns></returns>
public static bool TermialCheckCreate (TerminalType terminalType , GlobalParam.TelentParams telentParam = null , GlobalParam.SerialParams serialParam= null)
{
switch (terminalType)
{
case TerminalType.Telent:
{
if (terminalTelnetDictionary.ContainsKey(string.Format("Telnet:{0}", telentParam.telnetIp))) break;
if (telentParam == null) return false;
TelnetStrategy terminal = new TelnetStrategy(telentParam.telnetIp, GlobalParam.TELNET_PORT, 60);
terminalTelnetDictionary.Add(string.Format("Telnet:{0}",telentParam.telnetIp), terminal);
}
break;
case TerminalType.serial:
{
if (terminalSerialDictionary.ContainsKey(string.Format("Serial:{0}", serialParam.SerialCom))) break;
if (serialParam == null) return false;
SerialStrategy terminal = new SerialStrategy(GlobalParam.AppDirectory, serialParam.SerialCom, serialParam.SerialBaudRate);
terminalSerialDictionary.Add(string.Format("Serial:{0}",serialParam.SerialCom), terminal);
}
break;
}
return true;
}
}
abstract base and child showing only there names and constructors (if needed i"ll publish the entire code....)
public abstract class absTerminalStrategy
{
public abstract List<string> SendAndWaitForList(string Command);
public abstract bool WaitForOutPut(string Blocker, int secTimeOut);//implement Wait for Output string before releasing lock (Monitor.wait/Pulse)
}
public class SerialStrategy : absTerminalStrategy
{
public ScriptingSerial serailAgent = null;//Infrastructure
public SerialStrategy(string fullPathLog , string PortName , int Baudrate)
{
serailAgent = new ScriptingSerial(fullPathLog, PortName, Baudrate);
}
//....
}
public class TelnetStrategy : absTerminalStrategy
{
public static event SerialDataInput_EventHandler onDataInput;
public static ScriptingTelnet telnetAgent = null;//Infrastructure
public string TelnetIp = string.Empty;
public TelnetStrategy(string Ip, int Port, int CommandTimeOut)
{
TelnetIp = Ip;
int port = Port;
telnetAgent = new ScriptingTelnet(Ip, port, CommandTimeOut);
}
}

Passing custom object between Android activities in C#

I am creating an android app in VS2012 using Xamarin.Android. I am displaying a custom list in Main screen. I need to pass a custom object(with ID,String,String,String properties) from this Main activity to another when user clicks on list item.
Can anyone please help me with some example?
edit:
I have already tried solution mention in other question
but the problem is I am getting below exception:
This is how I am extracting in second activity
InsuranceReminderBO i = (InsuranceReminderBO)Intent.GetSerializableExtra("SelectedItemID");
i is null
and in first activity setting it like this:
Intent intent = new Intent(this, typeof(ReminderDetails));
intent.PutExtra("SelectedItemID", selectedInsurance);
StartActivity(typeof(ReminderDetails));
where class InsuranceReminderBO is defined as
public class InsuranceReminderBO : Java.Lang.Object, Java.IO.ISerializable
I have also tried using IParcelable but in that I got error Creator is not defined
in ICreator or Creator
Following the implementation of Iparcelable on CustomObject
'public class InsuranceReminderBO : Java.Lang.Object, IParcelable
{
public InsuranceReminderBO()
{
}
#region Objects and Properties
private int id;
private String strCompanyName;
private String strPremiumAmount;
private String stDueDate;
public int ID
{
get { return this.id; }
set { this.id = value; }
}
public String Company_Name
{
get { return this.strCompanyName; }
set { this.strCompanyName = value; }
}
public String Premium_Amount
{
get { return this.strPremiumAmount; }
set { this.strPremiumAmount = value; }
}
public String Due_Date
{
get { return this.stDueDate; }
set { this.stDueDate = value; }
}
#endregion
#region IParcelable implementation
// The creator creates an instance of the specified object
private static readonly GenericParcelableCreator<InsuranceReminderBO> _creator
= new GenericParcelableCreator<InsuranceReminderBO>((parcel) => new InsuranceReminderBO(parcel));
[ExportField("CREATOR")]
public static GenericParcelableCreator<InsuranceReminderBO> GetCreator()
{
return _creator;
}
// Create a new SelectListItem populated with the values in parcel
private InsuranceReminderBO(Parcel parcel)
{
ID = parcel.ReadInt();
Company_Name = parcel.ReadString();
Premium_Amount = parcel.ReadString();
Due_Date = parcel.ReadString();
}
public int DescribeContents()
{
return 0;
}
// Save this instance's values to the parcel
public void WriteToParcel(Parcel dest, ParcelableWriteFlags flags)
{
dest.WriteInt(ID);
dest.WriteString(Company_Name);
dest.WriteString(Premium_Amount);
dest.WriteString(Due_Date);
}
// Closest to the 'Java' way of implementing the creator
/*public sealed class SelectListItemCreator : Java.Lang.Object, IParcelableCreator
{
public Java.Lang.Object CreateFromParcel(Parcel source)
{
return new SelectListItem(source);
}
public Java.Lang.Object[] NewArray(int size)
{
return new SelectListItem[size];
}
}*/
#endregion
}
#region GenericParcelableCreator
/// <summary>
/// Generic Parcelable creator that can be used to create objects from parcels
/// </summary>
public sealed class GenericParcelableCreator<T> : Java.Lang.Object, IParcelableCreator
where T : Java.Lang.Object, new()
{
private readonly Func<Parcel, T> _createFunc;
/// <summary>
/// Initializes a new instance of the <see cref="ParcelableDemo.GenericParcelableCreator`1"/> class.
/// </summary>
/// <param name='createFromParcelFunc'>
/// Func that creates an instance of T, populated with the values from the parcel parameter
/// </param>
public GenericParcelableCreator(Func<Parcel, T> createFromParcelFunc)
{
_createFunc = createFromParcelFunc;
}
#region IParcelableCreator Implementation
public Java.Lang.Object CreateFromParcel(Parcel source)
{
return _createFunc(source);
}
public Java.Lang.Object[] NewArray(int size)
{
return new T[size];
}
#endregion
}
#endregion'
I am putting object in intent as
InsuranceReminderBO selectedInsurance = listOfInsurance[e.Position];
Intent intent = new Intent(this, typeof(ReminderDetails));
intent.PutExtra("SelectedItem", selectedInsurance);
And reading in second activity as
InsuranceReminderBO i = (InsuranceReminderBO)Intent.GetParcelableExtra("SelectedItem");
but getting i as null.
To coat tail on the servicestack.text solution, you can just download the android DLL's and reference them into your solution. You can use this and add it to your solution, build it separately, as alternatives. https://github.com/ServiceStack/ServiceStack.Text/tree/master/src/ServiceStack.Text.Android
Also I use a couple of methods to convert items back and forth that may be helpful, try
static public string ToJSON(this object item)
{
var myval = JsonSerializer.SerializeToString(item);
return myval;
}
static public T FromJSON<T>(string code)
{
var item = JsonSerializer.DeserializeFromString<T>(code);
return item;
}
There's an article on using IParcelable in Xamarin here.
Personally, I've always just serialised to JSON, passed a string extra and deserialised it on the other end.
If you're using ServiceStack.Text, which I like, you can do something like this:
intent.PutExtra("SelectedItemId", JsonSerializer.SerializeToString(selectedInsurance));
And on the other end:
var insurance = JsonSerializer.DeserializeFromString<InsuranceReminderBO>(Intent.GetStringExtra("SelectedItemId"))
No need to implement Java.Lang.Object, Java.IO.ISerializable
After doing a lot of search on Google finally i found a solution here.
Basically I used StartActivity(intent);

C# Immutable & Mutable types without duplication

Given the following implementation of mutable and immutable types, is there a way to avoid duplicate code (mainly the duplicate properties)?
I'd like to work with immutable type by default unless a mutable type is required (e.g. when binding to UI elements).
We're using .NET framework 4.0, but plan switching to 4.5 soon.
public class Person {
public string Name { get; private set; }
public List<string> Jobs { get; private set; } // Change to ReadOnlyList<T>
public Person() {}
public Person(Mutable m) {
Name = m.Name;
}
public class Mutable : INotifyPropertyChanged {
public string Name { get; set; }
public List<string> Jobs { get; set; }
public Mutable() {
Jobs = new List<string>();
}
public Mutable(Person p) {
Name = p.Name;
Jobs = new List<string>(p.Jobs);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName) {
// TODO: implement
}
}
}
public class Consumer {
public Consumer() {
// We can use object initializers :)
Person.Mutable m = new Person.Mutable {
Name = "M. Utable"
};
// Consumers can happily mutate away....
m.Name = "M. Utated";
m.Jobs.Add("Herper");
m.Jobs.Add("Derper");
// But the core of our app only deals with "realio-trulio" immutable types.
// Yey! Have constructor with arity of one as opposed to
// new Person(firstName, lastName, email, address, im, phone)
Person im = new Person(m);
}
}
I made something that does what you ask recently (using T4 templates), so it is absolutely possible:
https://github.com/xaviergonz/T4Immutable
For example, given this:
[ImmutableClass(Options = ImmutableClassOptions.IncludeOperatorEquals)]
class Person {
private const int AgeDefaultValue = 18;
public string FirstName { get; }
public string LastName { get; }
public int Age { get; }
[ComputedProperty]
public string FullName {
get {
return FirstName + " " + LastName;
}
}
}
It will automatically generate for you in a separate partial class file the following:
A constructor such as public Person(string firstName, string
lastName, int age = 18) that will initialize the values.
Working implementations for Equals(object other) and Equals(Person other).
Also it will add the IEquatable interface for you. Working
implementations for operator== and operator!=
A working implementation of GetHashCode() A better ToString() with output such as "Person { FirstName=John, LastName=Doe, Age=21 }"
A Person With(...) method that can be used to generate a new immutable clone with 0 or more properties changed (e.g. var janeDoe = johnDoe.With(firstName: "Jane", age: 20)
So it will generate this (excluding some redundant attributes):
using System;
partial class Person : IEquatable<Person> {
public Person(string firstName, string lastName, int age = 18) {
this.FirstName = firstName;
this.LastName = lastName;
this.Age = age;
_ImmutableHashCode = new { this.FirstName, this.LastName, this.Age }.GetHashCode();
}
private bool ImmutableEquals(Person obj) {
if (ReferenceEquals(this, obj)) return true;
if (ReferenceEquals(obj, null)) return false;
return T4Immutable.Helpers.AreEqual(this.FirstName, obj.FirstName) && T4Immutable.Helpers.AreEqual(this.LastName, obj.LastName) && T4Immutable.Helpers.AreEqual(this.Age, obj.Age);
}
public override bool Equals(object obj) {
return ImmutableEquals(obj as Person);
}
public bool Equals(Person obj) {
return ImmutableEquals(obj);
}
public static bool operator ==(Person a, Person b) {
return T4Immutable.Helpers.AreEqual(a, b);
}
public static bool operator !=(Person a, Person b) {
return !T4Immutable.Helpers.AreEqual(a, b);
}
private readonly int _ImmutableHashCode;
private int ImmutableGetHashCode() {
return _ImmutableHashCode;
}
public override int GetHashCode() {
return ImmutableGetHashCode();
}
private string ImmutableToString() {
var sb = new System.Text.StringBuilder();
sb.Append(nameof(Person) + " { ");
var values = new string[] {
nameof(this.FirstName) + "=" + T4Immutable.Helpers.ToString(this.FirstName),
nameof(this.LastName) + "=" + T4Immutable.Helpers.ToString(this.LastName),
nameof(this.Age) + "=" + T4Immutable.Helpers.ToString(this.Age),
};
sb.Append(string.Join(", ", values) + " }");
return sb.ToString();
}
public override string ToString() {
return ImmutableToString();
}
private Person ImmutableWith(T4Immutable.WithParam<string> firstName = default(T4Immutable.WithParam<string>), T4Immutable.WithParam<string> lastName = default(T4Immutable.WithParam<string>), T4Immutable.WithParam<int> age = default(T4Immutable.WithParam<int>)) {
return new Person(
!firstName.HasValue ? this.FirstName : firstName.Value,
!lastName.HasValue ? this.LastName : lastName.Value,
!age.HasValue ? this.Age : age.Value
);
}
public Person With(T4Immutable.WithParam<string> firstName = default(T4Immutable.WithParam<string>), T4Immutable.WithParam<string> lastName = default(T4Immutable.WithParam<string>), T4Immutable.WithParam<int> age = default(T4Immutable.WithParam<int>)) {
return ImmutableWith(firstName, lastName, age);
}
}
And there are some more features as explained in the project page.
PS: If you want a property that's a list of other immutable objects just add:
public ImmutableList<string> Jobs { get; }
No, there's no easy way to avoid duplicate code.
What you've implemented is effectivly the builder pattern. The .NET StringBuilder class follows the same approach.
The support for immutable types in C# is a bit lacking, and could do with some language specific features to make it easier. Having to create a builder is a real pain, as you've discovred. An alternative is to have a constructor that takes all the values, but you tend to end up with the mother of all constructors, which makes the code unreadable.
Since the properties don't have the same visibility, this is not duplicate code. If their visibilty were the same, Person could inherit from Mutable to avoid duplication. Right now, I don't think there is code to factorize in what you show.
Think about using code generation to map each mutable to its immutable equivalent.
I personally like T4 code generation, aided by T4Toolbox library.
You can quite easily parse your code using EnvDTE.
You can find tons of high-quality information about T4 on Oleg Sych blog
http://www.olegsych.com/
Code generation could be hard to handle in the beginning, but it solves the infamous issue of the code-that-must-be-duplicated.
One for your consideration depending on if you're creating a public facing API is to consider 'popcicle immutability' as discussed by Eric Lippert. The nice thing about this is you don't need any duplication at all.
I've used something in reverse, my classes are mutable until a certain point when some calculations are going to occur at which point I call a Freeze() method. All changes to properties call a BeforeValueChanged() method, which if frozen throws an exception.
What you need is something whereby the classes are frozen by default, and you unfreeze them if you need them mutable. As others have mentioned if frozen you need to be returning read only copies of lists etc.
Here's an example of a little class I put together:
/// <summary>
/// Defines an object that has a modifiable (thawed) state and a read-only (frozen) state
/// </summary>
/// <remarks>
/// All derived classes should call <see cref="BeforeValueChanged"/> before modifying any state of the object. This
/// ensures that a frozen object is not modified unexpectedly.
/// </remarks>
/// <example>
/// This sample show how a derived class should always use the BeforeValueChanged method <see cref="BeforeValueChanged"/> method.
/// <code>
/// public class TestClass : Freezable
/// {
/// public String Name
/// {
/// get { return this.name; }
/// set
/// {
/// BeforeValueChanged();
/// this.name = name;
/// }
/// }
/// private string name;
/// }
/// </code>
/// </example>
[Serializable]
public class Freezable
{
#region Locals
/// <summary>Is the current instance frozen?</summary>
[NonSerialized]
private Boolean _isFrozen;
/// <summary>Can the current instance be thawed?</summary>
[NonSerialized]
private Boolean _canThaw = true;
/// <summary>Can the current instance be frozen?</summary>
[NonSerialized]
private Boolean _canFreeze = true;
#endregion
#region Properties
/// <summary>
/// Gets a value that indicates whether the object is currently modifiable.
/// </summary>
/// <value>
/// <c>true</c> if this instance is frozen; otherwise, <c>false</c>.
/// </value>
public Boolean IsFrozen
{
get { return this._isFrozen; }
private set { this._isFrozen = value; }
}
/// <summary>
/// Gets a value indicating whether this instance can be frozen.
/// </summary>
/// <value>
/// <c>true</c> if this instance can be frozen; otherwise, <c>false</c>.
/// </value>
public Boolean CanFreeze
{
get { return this._canFreeze; }
private set { this._canFreeze = value; }
}
/// <summary>
/// Gets a value indicating whether this instance can be thawed.
/// </summary>
/// <value>
/// <c>true</c> if this instance can be thawed; otherwise, <c>false</c>.
/// </value>
public Boolean CanThaw
{
get { return this._canThaw; }
private set { this._canThaw = value; }
}
#endregion
#region Methods
/// <summary>
/// Freeze the current instance.
/// </summary>
/// <exception cref="System.InvalidOperationException">Thrown if the instance can not be frozen for any reason.</exception>
public void Freeze()
{
if (this.CanFreeze == false)
throw new InvalidOperationException("The instance can not be frozen at this time.");
this.IsFrozen = true;
}
/// <summary>
/// Does a Deep Freeze for the duration of an operation, preventing it being thawed while the operation is running.
/// </summary>
/// <param name="operation">The operation to run</param>
internal void DeepFreeze(Action operation)
{
try
{
this.DeepFreeze();
operation();
}
finally
{
this.DeepThaw();
}
}
/// <summary>
/// Applies a Deep Freeze of the current instance, preventing it be thawed, unless done deeply.
/// </summary>
internal void DeepFreeze()
{
// Prevent Light Thawing
this.CanThaw = false;
this.Freeze();
}
/// <summary>
/// Applies a Deep Thaw of the current instance, reverting a Deep Freeze.
/// </summary>
internal void DeepThaw()
{
// Enable Light Thawing
this.CanThaw = true;
this.Thaw();
}
/// <summary>
/// Thaws the current instance.
/// </summary>
/// <exception cref="System.InvalidOperationException">Thrown if the instance can not be thawed for any reason.</exception>
public void Thaw()
{
if (this.CanThaw == false)
throw new InvalidOperationException("The instance can not be thawed at this time.");
this.IsFrozen = false;
}
/// <summary>
/// Ensures that the instance is not frozen, throwing an exception if modification is currently disallowed.
/// </summary>
/// <exception cref="System.InvalidOperationException">Thrown if the instance is currently frozen and can not be modified.</exception>
protected void BeforeValueChanged()
{
if (this.IsFrozen)
throw new InvalidOperationException("Unable to modify a frozen object");
}
#endregion
}

Solving a library design - centralised configuration reference

Consider the sample code below consisting of a Class Library design and an executable Program using the library.
namespace AppLib
{
/// <summary>
/// Entry point for library. Stage manages all the actors in the logic.
/// </summary>
class StageApp
{
/// <summary>
/// Setting that is looked up by different actors
/// </summary>
public int SharedSetting { get; set; }
/// <summary>
/// Stage managing actors with app logic
/// </summary>
public IEnumerable<Actor> Actors { get { return m_actors.Where(x => x.Execute() > 40).ToArray(); } }
private List<Actor> m_actors = new List<Actor>();
}
/// <summary>
/// An object on the stage. Refers to stage (shared)settings and execute depending on the settings.
/// Hence actor should have reference to stage
/// </summary>
class Actor
{
private StageApp m_StageApp;
private int m_Property;
/// <summary>
/// An actor that needs to refer to stage to know what behavior to execute
/// </summary>
/// <param name="stage"></param>
public Actor(StageApp stage)
{
m_StageApp = stage;
m_Property = new Random().Next();
}
/// <summary>
/// Execute according to stage settings
/// </summary>
/// <returns></returns>
public int Execute()
{
return m_StageApp.SharedSetting * m_Property;
}
}
}
namespace AppExe
{
using AppLib;
class Program
{
static void Main(string[] args)
{
StageApp app = new StageApp();
app.SharedSetting = 5;
// Question: How to add actor to stage?
foreach (var actor in app.Actors)
Console.WriteLine(actor.Execute());
}
}
}
Question
Stage and Actor have circular dependency and seems bad to me.
For example, how should we add actors to stage?
If I let user to create new Actor() themselves,
then they must keep on supplying the Stage.
If I give Actor() an internal constructor and make Stage a factory,
then I lose some of the flexibility for users to do making inherited Actors.
If I make Stage a singleton, then I can only have one set of SharedSetting.
In case the user wants more than one Stage in his AppExe, then it cannot be done.
Is there anyway to redesign the architecture so as to avoid the problems above?
If your functionality is not limited by sharing the StageApp settings between actors, but also will be some other logic. For example when you need to know parent StageApp from Actor and vice versa. I preffer to implement it in this way:
namespace AppLib
{
/// <summary>
/// Entry point for library. Stage manages all the actors in the logic.
/// </summary>
class StageApp
{
/// <summary>
/// Setting that is looked up by different actors
/// </summary>
public int SharedSetting { get; set; }
/// <summary>
/// Stage managing actors with app logic
/// </summary>
public IEnumerable<Actor> Actors { get { return m_actors.Where(x => x.Execute() > 40).ToArray(); } }
private List<Actor> m_actors = new List<Actor>();
public int TotalActorsCount
{
get
{
return m_actors.Count;
}
}
public void AddActor(Actor actor)
{
if (actor == null)
throw new ArgumentNullException("actor");
if (m_actors.Contains(actor))
return; // or throw an exception
m_actors.Add(actor);
if (actor.Stage != this)
{
actor.Stage = this;
}
}
// we are hiding this method, to avoid because we can change Stage only to another non null value
// so calling this method directly is not allowed
internal void RemoveActor(Actor actor)
{
if (actor == null)
throw new ArgumentNullException("actor");
if (!m_actors.Contains(actor))
return; // or throuw exception
m_actors.Remove(actor);
}
}
/// <summary>
/// An object on the stage. Refers to stage (shared)settings and execute depending on the settings.
/// Hence actor should have reference to stage
/// </summary>
class Actor
{
private StageApp m_StageApp;
private int m_Property;
public StageApp Stage
{
get
{
return m_StageApp;
}
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
if (m_StageApp != value)
{
if (m_StageApp != null) // not a call from ctor
{
m_StageApp.RemoveActor(this);
}
m_StageApp = value;
m_StageApp.AddActor(this);
}
}
}
/// <summary>
/// An actor that needs to refer to stage to know what behavior to execute
/// </summary>
/// <param name="stage"></param>
public Actor(StageApp stage)
{
Stage = stage;
m_Property = new Random().Next();
}
/// <summary>
/// Execute according to stage settings
/// </summary>
/// <returns></returns>
public int Execute()
{
return m_StageApp.SharedSetting * m_Property;
}
}
}
namespace AppExe
{
using AppLib;
class Program
{
static void Main(string[] args)
{
StageApp app = new StageApp();
app.SharedSetting = 5;
StageApp anotherApp = new StageApp();
anotherApp.SharedSetting = 6;
// actor is added to the stage automatically after instantiation
Actor a1 = new Actor(app);
Actor a2 = new Actor(app);
Actor a3 = new Actor(anotherApp);
Console.WriteLine("Actors in anotherApp before moving actor:");
Console.WriteLine(anotherApp.TotalActorsCount);
// or by calling method from StageApp class
anotherApp.AddActor(a1);
Console.WriteLine("Actors in anotherApp after calling method (should be 2):");
Console.WriteLine(anotherApp.TotalActorsCount);
// or by setting Stage through property
a2.Stage = anotherApp;
Console.WriteLine("Actors in anotherApp after setting property of Actor instance (should be 3):");
Console.WriteLine(anotherApp.TotalActorsCount);
Console.WriteLine("Actors count in app (should be empty):");
Console.WriteLine(app.TotalActorsCount);
}
}
}
It allows to you to manipulate with object relationships transparently, but requires a little bit mor code to implement.
How about adding a new class "ActorRole" that defines the behaviour of the actor in each Stage. It lets you decouple Actor and Stage from each other, so you can instantiate both independently (through a factory for example) and then combine them creating ActorRole objects that configure your stages. This combinations can be made using a Builder pattern if it is needed.
If you need to dynamically change your actor behaviour, you can use a Strategy pattern based on the ActorRole class, so depending on the Stage, you can assign to the actor different concrete implementations of its behaviour.
I would solve it by using Func instead of passing in the Stage to the Actor. Like this:
namespace AppExe
{
using AppLib;
class Program
{
static void Main(string[] args)
{
StageApp app = new StageApp();
app.CreateActor();
app.SharedSetting = 5;
foreach (var actor in app.Actors)
Console.WriteLine(actor.Execute());
}
}
}
namespace AppLib
{
class StageApp
{
public int SharedSetting { get; set; }
public IEnumerable<Actor> Actors { get { return m_actors.Where(x => x.Execute() > 40).ToArray(); } }
private List<Actor> m_actors = new List<Actor>();
public void CreateActor()
{
m_actors.Add(new Actor(Executed));
}
private int Executed(int arg)
{
return SharedSetting * arg;
}
}
class Actor
{
private int m_Property;
private Func<int, int> m_executed;
public Actor(Func<int, int> executed)
{
m_executed = executed;
m_Property = new Random().Next();
}
public int Execute()
{
return m_executed(m_Property);
}
}
}
I totally agree with you that circular references is not fun :).
You could also solve this using events, but I like passing functions like callback.

Categories