Shortly speaking
Let's say I have the following code:
// a class like this class FirstObject { public Object OneProperty { get; set; } // (other properties) public Object OneMethod() { // logic } } // and another class with properties and methods names // which are similar or exact the same if needed class SecondObject { public Object OneProperty { get; set; } // (other properties) public Object OneMethod(String canHaveParameters) { // logic } } // the consuming code would be something like this public static void main(String[] args) { FirstObject myObject=new FirstObject(); // Use its properties and methods Console.WriteLine("FirstObject.OneProperty value: "+myObject.OneProperty); Console.WriteLine("FirstObject.OneMethod returned value: "+myObject.OneMethod()); // Now, for some reason, continue to use the // same object but with another type // -----> CHANGE FirstObject to SecondObject HERE <----- // Continue to use properties and methods but // this time calls were being made to SecondObject properties and Methods Console.WriteLine("SecondObject.OneProperty value: "+myObject.OneProperty); Console.WriteLine("SecondObject.OneMethod returned value: "+myObject.OneMethod(oneParameter)); }
Is it possible to change the type of FirstObject to SecondObject and continue to use its properties and methods?
I have full control over FirstObject , but SecondObject sealed and completely out of my scope!
Can I achieve this through reflection? How? What do you think of the work this can do for this? Obviously, both classes can be LOT more complex than the example above.
Both classes can have patterns like FirstObject<T> and SecondObject<T> , which scare me from using reflection for such a task!
Problem in reality
I tried to formulate my problem in a simpler way for simplicity and try to extract some knowledge to solve it, but, looking at the answers, it seems obvious to me that to help me you need to understand my real problem, because changing the type of an object is only tip of the iceberg.
I am developing a workflow definition API . The main goal is that the API can be reused on top of any engine that I could use (CLR via WF4, NetBPM, etc.).
I am currently writing a middle tier to translate this API into WF4 to run workflows through the CLR.
What i have already done
The API concept at this point is somehow similar to WF4 with ActivityStates with In / Out Arguments and Data ( Variables ) passing through ActivityStates using their arguments.
Very simplified pseudo-code API:
class Argument { object Value; } class Data { String Name; Type ValueType; object Value; } class ActivityState { String DescriptiveName; } class MyIf: ActivityState { InArgument Condition; ActivityState Then; ActivityState Else; } class MySequence: ActivityState { Collection<Data> Data; Collection<ActivityState> Activities; }
My initial approach for translating this to WF4 was too much triggered through the ActivitiesStates schedule and somehow directly assigning properties using reflection where needed.
Simplified pseudo code again, something like:
new Activities.If() { DisplayName=myIf.DescriptiveName, Condition=TranslateArgumentTo_WF4_Argument(myIf.Condition), Then=TranslateActivityStateTo_WF4_Activity(myIf.Then), Else=TranslateActivityStateTo_WF4_Activity(myIf.Else) } new Activities.Sequence() { DisplayName=mySequence.DescriptiveName, Variables=TranslateDataTo_WF4_Variables(mySequence.Variables), Activities=TranslateActivitiesStatesTo_WF4_Activities(mySequence.Activities) }
At the end of the translation, I will have the System.Activities.Activity executable. I already made it easy.
A big problem
A big problem with this approach came when I started to convert a System.Activities.Variable Data object. The problem is that WF4 separates workflow execution from context. Because of this, both Arguments and Variables have LocationReferences , which must be accessed through the var.Get(context) function, so that the engine knows where they are at runtime.
Something like this is easy to do with WF4:
Variable<string> var1=new Variable<string>("varname1", "string value"); Variable<int> var2=new Variable<int>("varname2", 123); return new Sequence { Name="Sequence Activity", Variables=new Collection<Variable> { var1, var2 }, Activities=new Collection<Activity>(){ new Write() { Name="WriteActivity1", Text=new InArgument<string>( context => String.Format("String value: {0}", var1.Get(context))) }, new Write() {
but if I want to present the same workflow through my API:
Data<string> var1=new Data<string>("varname1", "string value"); Data<int> var2=new Data<int>("varname2", 123); return new Sequence() { DescriptiveName="Sequence Activity", Data=new Collection<Data> { var1, var2 }, Activities=new Collection<ActivityState>(){ new Write() { DescriptiveName="WriteActivity1", Text="String value: "+var1
As a result, I am a BIG PROBLEM when using Data objects as Variable s. I really don't know how to allow a developer, using my API, to use Data objects wherever they want (as in WF4), and then translate that Data into System.Activities.Variable .
Decisions come to mind
If you now understand my problem, FirstObject and SecondObject are Data and System.Activities.Variable respectively . As I said, translating Data into Variable is just the tip of the iceberg, because I can use Data.Get() in my code and donβt know how to translate it to Variable.Get(context) when doing the translation.
The solutions I tried about:
Solution 1
Instead of translating properties directly, I would develop NativeActivites for each flow control activity ( If , Sequence , Switch , ...) and use the CacheMetadata() function to specify Arguments and Variables . The problem is that it is accessed through var.Get(context) .
Decision 2
Give my Data class its own Get() function. It would be only an abstract method, without logic inside, which somehow translates the System.Activities.Variable function to Get() . Is this possible with C #? I think no! Another problem is that a Variable.Get() has one parameter.
Decision 3
The worst solution I was thinking of was CIL-manipulation . Try replacing the code in which Data/Argument used with the Variable/Argument code. It smells like a nightmare for me. I know almost nothing about System.reflection.Emit , and even if I find out, I assume that it will take an age ... and maybe it won't even succeed.
Sorry if I ended up presenting a big problem, but I really got stuck here and desperately needed a clue / way to continue.