Dynamic type expansion at runtime?

I need to extend instances of different types at runtime. In most cases, I need to work with instances of the source type, but in some cases I need to create an extension wrapper around those types that add a couple of pieces of contextual information. Something in the lines of the following (which is not really valid .NET / C # code ... but this illustrates the point):

public abstract class BaseClass { // ... } public class Concrete1: BaseClass { // ... } public class Concrete2: BaseClass { // ... } public class WrapperExtender<T>: T // Extending from T here is actually invalid! where T: BaseClass { public WrapperExtender(T extensionTarget) { m_extensionTarget = extensionTarget; } private readonly T m_extensionTarget; public object ContextualReference { get; } public int ContextualValue { get; } // DERP: Would need to implement overrides of T here...buuut...can't... } // In use, special case: var instance = new Concrete1(); var extendedInstance = new WrapperExtender(instance); var processor = new SomeProcessorRequiringExtendedInstance(); processor.DoProcessing(extendedInstance); 

Another example of this might be Microsoft Entity Framework v4.0 or nHibernate. Both of these structures provide dynamically expanded instances of the types of your entities, wrapping them internally to provide the runtime hooks needed to constantly update the data context / object / session with the changes made to the entity instances. My needs are not so complex, and the generic script described above will work beautifully, at least one way to combine generics and dynamic typing.

Anyway, I hope someone knows how to achieve the above scenario. Or maybe even better, someone knows a better solution. I don't care about the idea of โ€‹โ€‹dynamically expanding this type at runtime (it doesn't have the same meaning as in the EF / nHibernate script). At the moment, this is the only thing I can really think of, this will provide me with the information that I need in the processor for each type passed to DoProcessing.

+4
source share
4 answers

Found a better solution than temporary expansion. I created the actual context object, which was the state that I needed. Whenever this context exists, I initialize the context and set a static property that can be used to retrieve the context object from anywhere, making it easier to update all the dependencies of my larger process to accept the context as a parameter (which isnโ€™t always possible, as sometimes calls are made in other contexts.)

 public class SomeContext { public SomeContext(object stateData1, object stateData2) { StateData1 = stateData1; StateData2 = stateData2; } public virtual object StateData1 { get; private set; } public virtual object StateData2 { get; private set; } [ThreadStatic] private static SomeContext m_threadInstance; public static SomeContext Current { get { return m_threadInstance; } set { if (value != null && m_threadInstance != null) throw new InvalidOperationException("This context has already been initialized for the current thread."); m_threadInstance = value; } } } public class SomeContextScope: IDisposable { public SomeContextScope(object stateData1, object stateData2) { if (SomeContext.Current == null) { SomeContext context = new SomeContext(stateData1, stateData2); SomeContext.Current = context; m_contextCreated = true; } } private bool m_contextCreated; public void Dispose() { if (m_contextCreated) { SomeContext.Current = null; } } } public class ComplexProcessor { public ComplexProcessor(...) // Lots of dependencies injected public void DoProcessing(BaseClass instance) { // do some work with instance if (SomeContext.Current != null) { // do contextually sensitive stuff for SomeContext with instance // call a dependency that does contextually sensitive stuff } // do some more work with instance // call a dependency that does contextually sensitive stuff if (SomeOtherContext.Current != null) { // do contextually sensitive stuff for SomeOtherContext with instance // call a dependency that does contextually sensitive stuff } // call a dependency that does contextually sensitive stuff } } // The original setup of the context and initiation of processing public void SomeOperation(...) { using (SomeContextScope scope = new SomeContextScope(stateData1, stateData2)) { // ... do some work var processor = complexProcessorFactory.CreateInstance(); processor.DoProcesing(data); // ... do more work } } 

I love the way it works. Context is the state in which the behavior is executed. It has always been inconvenient for me to pass contextual data to other objects and have many methods or method overloads that accept and transmit various forms of contextual data. By creating a context object that is available globally all the time, my code is much cleaner and my dependencies are more concise. This should also be mocked, since the Current property is read / write, I can create a context layout in the BDD or TDD unit test specification when one of them is required without much hassle.

0
source

The problems that EF, etc. resolve, are varied and related to types such as lazy loading, etc. I'm just not sure what level of complexity a dynamic subclass requires for this scenario. A few thoughts:

  • you have a bag of properties in your object for flexible additional properties; if necessary, the property package can be exposed to the data binding API via ICustomTypeDescriptor
  • just wrap your object in an implementation-specific tuple that contains an existing object and additional properties (without a subclass)

Too bad C # doesn't support mixins, which would also be a good way to implement this type of thing with interfaces.

+2
source

I know that this can be done using dynamicproxy (which is what NHibernate uses to complete this task), which you can learn about here:

DynamicProxy Page

DynamicProxy Tutorial

+1
source

If you need additional properties, why not just create a context property in BaseClass?

something like this where the ContextBag is either a general collection class or a specially defined collection of contexts:

 Public ContextBag Context { get; set; } 

When setting up / accessing the context, you will use the syntax as follows:

 SubClass.Context.GetInt(ContextDefinition, ContextName); SubClass.Context.Add(ContextDefinition, ContextName, ContextValue); 
+1
source

All Articles