Skip to content

Instantly share code, notes, and snippets.

@ifandelse
Created May 6, 2011 02:10
Show Gist options
  • Save ifandelse/958333 to your computer and use it in GitHub Desktop.
Save ifandelse/958333 to your computer and use it in GitHub Desktop.
Trying to work out a way for a Memento Reset's behavior to be unknown/transparent to target domain model
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace ResetIdeas
{
class Program
{
static void Main(string[] args)
{
var person = new Person();
var memento = new PersonMemento()
{
FirstName = "Jim",
LastName = "Cowart",
PersonId = "12345",
Ssn = "555-55-5555"
};
memento.Reset( person );
Console.WriteLine(person.ToString());
Console.ReadLine();
}
}
public class Person : IPerson
{
public string FirstName { get; private set; }
public string LastName { get; private set; }
public string PersonId { get; private set; }
public string Ssn { get; private set; }
public override string ToString()
{
return String.Format("FirstName:{0}, LastName:{1}, PersonId:{2}, Ssn:{3}", FirstName, LastName, PersonId, Ssn);
}
}
public class PersonMemento
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string PersonId { get; set; }
public string Ssn { get; set; }
public void Reset(Person instance)
{
dynamic dInstance = new PrivateSetterProxy(instance);
dInstance.FirstName = FirstName;
dInstance.LastName = LastName;
dInstance.PersonId = PersonId;
dInstance.Ssn = Ssn;
}
}
public interface IHaveFirstName
{
string FirstName { get; }
}
public interface IHaveLastName
{
string LastName { get; }
}
public interface IHavePersonId
{
string PersonId { get; }
}
public interface IHaveSsn
{
string Ssn { get; }
}
public interface IPerson : IHaveFirstName, IHaveLastName, IHavePersonId, IHaveSsn
{
}
public class PrivateSetterProxy : DynamicObject
{
private readonly object _instance;
private readonly Type _instanceType;
private const BindingFlags BindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
public PrivateSetterProxy(object instance)
{
_instance = instance;
_instanceType = _instance.GetType();
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if ( TrySettingProperty( binder, value ) ) return true;
return TrySettingField( binder, value );
}
private bool TrySettingField( SetMemberBinder binder, object value )
{
var fieldInfo = _instanceType.GetField(binder.Name, BindingFlags);
if (fieldInfo != null)
{
fieldInfo.SetValue(_instance, value);
return true;
}
return false;
}
private bool TrySettingProperty( SetMemberBinder binder, object value )
{
var propertyInfo = _instanceType.GetProperty(binder.Name, BindingFlags);
if (propertyInfo != null)
{
propertyInfo.SetValue(_instance, value, null);
return true;
}
return false;
}
}
}
@troydemonbreun
Copy link

I like this approach, that is, the POCO/PI approach to the Memento. Too bad for the performance hit, though. It's great to see these Spikes, thanks for sharing.

@ifandelse
Copy link
Author

Troy - thanks a ton for looking at it. I hadn't heard Fowler's description of "PI" - but I think that's a great description for it especially when trying to explain it to peers who are used to seeing the persistence concern mixed in...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment