Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong>Summary</strong></p> <p>Use interception to address cross cutting concerns in how your properties are implemented. </p> <p>Attributes can be used to associate static metadata to your code, whilst runtime dependencies require a bit more configuration.</p> <hr> <p><strong>Explanation and Example</strong></p> <p>My understanding is that you are essentially concerned with an exercise in <a href="http://en.wikipedia.org/wiki/Aspect-oriented_programming" rel="nofollow">Aspect Orientated Programming</a>. You wish to decouple the definition of your class, to the way the underlying data is persisted and any subsequent consequences (such as the raising of the <code>INotifyPropertyChanged</code> event).</p> <p>What's interesting about your case is that you wish to do using both static data (the string value <code>"TextAccount"</code> in your code sample) and data that is only known at runtime (the <code>this.TabAccountLangs</code> in your code example). These types of data require different approaches.</p> <p>There is quite a bit going on in my solution, but let me first post the code and then explain it:</p> <pre><code>internal class Program { private static void Main(string[] args) { var cOldClass = new PlainOldClass(); var classProxyWithTarget = new ProxyGenerator().CreateClassProxyWithTarget(cOldClass,new Intercetor(cOldClass)); classProxyWithTarget.PropertyOne = 42; classProxyWithTarget.PropertyTwo = "my string"; } } [AttributeUsage(AttributeTargets.Property)] public class StaticDataAttribute : Attribute { public string StaticData { get; private set; } public StaticDataAttribute(string resourceKey) { StaticData = resourceKey; } } public interface IMyRuntimeData { string TabAccountLangs { get; } void OnPropertyChanged(string propertyName = null); } public class PlainOldClass : IMyRuntimeData { [StaticData("FirstProperty")] public virtual int PropertyOne { get; set; } public string PropertyTwo { get; set; } public event PropertyChangedEventHandler PropertyChanged; public string TabAccountLangs { get; private set; } public virtual void OnPropertyChanged(string propertyName = null) { var handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } } public class Intercetor: IInterceptor { private readonly IMyRuntimeData _runtimeData; public Intercetor(IMyRuntimeData runtimeData) { _runtimeData = runtimeData; } public void Intercept(IInvocation invocation) { var isPropertySetter = invocation.Method.Name.StartsWith("set_"); var isPropertyGetter = invocation.Method.Name.StartsWith("get_"); if (isPropertySetter) { //Pre Set Logic invocation.Proceed(); //Post Set Logic var attribute = invocation.Method.GetCustomAttributes(false).Cast&lt;StaticDataAttribute&gt;().SingleOrDefault(); if (attribute != null) { string resourceKey = attribute.StaticData; string tabAccountLangs = _runtimeData.TabAccountLangs; _runtimeData.OnPropertyChanged(invocation.Method.Name.Substring(4)); } } else if (isPropertyGetter) { //Pre Get Logic invocation.Proceed(); //Post Get Logic } else { invocation.Proceed(); } } } </code></pre> <p>I rely heavily on <strong>interception</strong> to address cross cutting concerns. I have used Castle's <a href="http://www.castleproject.org/projects/dynamicproxy/" rel="nofollow">Dynamic Proxy</a> in my implementation of the <code>IInterceptor</code> interface. The actual logic isn't important or maybe relevant to your needs - but it should at least give a conceptual view of how you can achieve what you want in your specific situation.</p> <p>The properties I care about are marked as <code>virtual</code> (so the Dynamic Proxy intercepts calls to them), and decorated with the <code>StaticDataAttribute</code>, to allow me to attach static data to each property. The trickier part is those aspects of the interception that rely on data that is not determined until runtime, that is the raising of the property changed event, and using the value of <code>this.TabAccountLangs</code>. These "runtime dependencies" are encapsulated within the interface <code>IRuntimeData</code>, which is injected in to the constructor of the interceptor. </p> <p>The <code>Main(string[] args)</code> method shows how everything is put together. Obviously you wouldn't use it like this in code - you could wrap this "gluing" logic within a factory pattern, or configure the interception at the level of your IoC container configuration.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload