Created
May 6, 2011 02:10
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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...