Take the following C# code
namespace lib.foo {
public class A {
public A (int x) {}
public int GetNumber() { return calculateNumber(); }
private int calculateNumber() { return lib.bar.B.ProduceNumber(); }
public void irrelevantMethod() {}
}
}
namespace lib.bar {
public class B {
public static int ProduceNumber() { return something; }
public void IrrelevantMethod() {}
}
}
I want to produce an assembly that contains the functionality of lib.foo.A.GetNumber(), store it, and later load it dynamically and then execute it.
In order for that to work, I'd need a program that can trace all the required dependencies (listed below), and emit them - including their implementation(!) - in one assembly for storage.
* lib.foo.A(int)
* lib.foo.A.getNumber()
* lib.foo.A.calculateNumer()
* lib.bar.B.ProduceNumber()
Can it be done? How?
In case anyone is wondering, I want to build a system where machine A tells machine B (using WCF) what to do. Since serializing delegates is impossible, my plan is to
1) transport an assembly from machine A to B,
2) load the assembly on machine B,
3) have machine A instruct machine B to invoke the desired method, which is implemented in this new assembly.
Note - this isn't really an answer, more of a nitpicking correction (of sorts)..
When you say "Since serializing delegates is impossible", this isn't strictly true, although I would NOT recommend doing it. This example code effectively "serializes" a delegate:
void Main()
{
Func<int,int> dlgt = FuncHolder.SomeMethod;
var ser = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
byte[] buffer;
using(var ms = new MemoryStream())
{
ser.Serialize(ms, dlgt);
buffer = ms.ToArray();
}
Console.WriteLine("{0} was serialized to {1} bytes", dlgt.GetType().Name, buffer.Length);
using(var ms = new MemoryStream(buffer))
{
dynamic whatzit = ser.Deserialize(ms);
whatzit(1);
}
}
[Serializable]
public struct FuncHolder
{
public static int SomeMethod(int i)
{
Console.WriteLine("I was called with {0}, returning {1}", i, i+1);
return i+1;
}
}
Output:
Func`2 was serialized to 978 bytes
I was called with 1, returning 2
I must emphasize, however, that you probably shouldn't do this. :)
As for the original question:
I'd be very careful about transporting and executing arbitrary code, especially in a production environment; the potential for security breaches is considerable, mainly via injection routes. If you were to take, for example, one of the above suggestions and just blast over the source to execute dynamically, there's little stopping someone from injecting who-knows-what into your "Give me code to run" service.
You'd really need to spell out your exact needs here to really come up with a "good" solution, as there are multiple ways to accomplish the same basic idea:
as mentioned, pass actual source code to the service to load/compile/execute, potentially in a "sandbox" for some aspect of security/protection
distribute all executable code paths in a shared plugin/assembly which is pushed by some trusted process to all remote servers, and reduce your executor code to a single "DoWork" method invocation (i.e., wrap all the details inside the plugin)
Cobble together a rough DSL or other type of pseudo-language, restricted in what it can/can't do, and pass that source around.
rely on .NET remoting: actually go remotely call the methods in the assembly on a remote object via proxy.
Related
When using Apache Thrift [https://github.com/apache/thrift] to create a non blocking server in C#, the following Classes/Types cannot be recognized:
TNonblockingServerTransport
TNonblockingServer
I want to send command from my win10 laptop to control a time-consuming calculation performed on a high performance server (ubuntu). That's why I came to Apache Thrift. I have found the official C# version tutorial [https://github.com/apache/thrift/tree/master/tutorial/csharp] and it works well. This tutorial uses the so-called Blocking Mode (TSimpleServer). But in my situation, the time-consuming calculation procedure should be interrupt-able. Consequently, I must use a non-blocking server.
The logic is simple. For the server, I used a private flag forceStop. If the Client call Stop(), forceStop will set to true and the calculation loop will break.
// #Server#
// Server Set-Up
private void SetUp()
{
try
{
CalculatorHandler handler = new CalculatorHandler();
Calculator.Processor processor = new
Calculator.Processor(handler);
var serverTransport = new TServerSocket(9090);
TServer server = new TSimpleServer(processor, serverTransport);
// Use this for a multithreaded server
// server = new TThreadPoolServer(processor, serverTransport);
Console.WriteLine("Starting the server...");
server.Serve();
}
catch (Exception x)
{
Console.WriteLine(x.StackTrace);
}
}
private bool forceStop;
public int TimeConsumingOperation(int n1, int n2)
{
Console.WriteLine("add({0},{1})", n1, n2);
for (int i = 0; i < 10; i++)
{
//calculating
Thread.Sleep(500);
if (forceStop)
{
Quit();
}
}
return n1 + n2;
}
public void Stop()
{
forceStop = true;
}
// Client
// Button#1 Click callback
private void Button_Start_Click()
{
client.TimeConsumingOperation(0,0);
}
// Button#2 Click callback
private void Button_Stop_Click()
{
client.Stop();
}
//
I've found some useful examples in java [https://chamibuddhika.wordpress.com/2011/10/02/apache-thrift-quickstart-tutorial/]. I've try my best to convert the java code of non-block server to the corresponding C# code but I found that there seems to be no TNonblockingServerTransport in C#. Anyone could help me with this probelm?
// Java Code
public class NonblockingServer {
private void start() {
try {
TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(7911);
ArithmeticService.Processor processor = new ArithmeticService.Processor(new ArithmeticServiceImpl());
TServer server = new TNonblockingServer(new TNonblockingServer.Args(serverTransport).
processor(processor));
System.out.println("Starting server on port 7911 ...");
server.serve();
} catch (TTransportException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
NonblockingServer srv = new NonblockingServer();
srv.start();
}
}
There's actually two answers to that question.
Possible implementation
Your setup is flawed, to begin with.
// #Server#
// Server Set-Up
private bool forceStop;
public void Stop()
{
forceStop = true;
}
Let's assume, we have two clients, both starting a new calculation. Now one client wants to abort. What happens?
The solution would be to structure it in a way where the calculation is a separate business logic object that is instantiated at TimeConsumingOperation() and made available to the client by some means, typically by returning some sort of ID.
When the client now wants to abort, it calls Stop(calcualtionID). The server side logic now routes that call to the implementation and triggers whatever the abort mechanism might be, with C# is is probably a CancellationToken.
A third call would be needed to query the final results from the server end once the calculation has finished. Note that we still work with a TSimpleServer and the reason it works is because we avoid blocking calls by means of the API design.
Nonblocking server
Yes, there is no implementation yet for C#. Since Thrift is Open Source, that probably simply means that there were nobody running into that use case so far and wanted to spend time on an implementation. That is not to say that such a use case may not exist.
What exists are
Threaded and Threadpool servers
Task.Run(() => { your code })
which may help to solve your use case. Also, when used with ASP.NET there is no need for a nonblocking server since the runtime offers enough support already for multiple connections.
Bottom line
There are certain ways to work around that limitation you experierenced. One additional alternative could be to become a contributor by porting one of the existing (e.g. Java) nonblocking implementation to NetStd (preferred, since C# and NetCore will mature into "deprecated" state with the next release and both be replaced by NetStd eventually)
In C++ I have the following struct from 3rd-party code:
typedef struct NodeInfoTag
{
long lResult;
int bComplete;
char *pszNodeAddr;
char *pszParentAddr;
RTS_WCHAR *pwszNodeName;
RTS_WCHAR *pwszDeviceName;
RTS_WCHAR *pwszVendorName;
unsigned long ulTargetType;
unsigned long ulTargetId;
unsigned long ulTargetVersion;
unsigned short wMaxChannels;
}NodeInfotyp;
And the definition to RTS_WCHAR:
# ifndef RTS_WCHAR_DEFINED
# define RTS_WCHAR_DEFINED
typedef wchar_t RTS_WCHAR; /* wide character value */
# endif
(So it's basically a wchar_t)
Then I have my own class called CScanNetworkCallback, which extends the CPLCHandlerCallback class, a class from the same vendor:
.h file:
class CScanNetworkCallback : public CPLCHandlerCallback
{
public:
bool bScanComplete;
NodeInfotyp* pNodeInfo;
NodeInfotyp* pNodeInfoList;
std::vector<NodeInfotyp> vList;
CScanNetworkCallback();
virtual ~CScanNetworkCallback(void);
virtual long Notify(CPLCHandler *pPlcHandler, CallbackAddInfoTag CallbackAdditionalInfo);
};
The implementation follows their own guidelines with some of my own stuff thrown in:
CScanNetworkCallback::CScanNetworkCallback(void) : CPLCHandlerCallback()
{
bScanComplete = false;
}
CScanNetworkCallback::~CScanNetworkCallback()
{
delete pNodeInfo;
delete pNodeInfoList;
}
long CScanNetworkCallback::Notify(CPLCHandler *pPlcHandler, CallbackAddInfoTag CallbackAdditionalInfo)
{
if (pPlcHandler != NULL)
{
if (CallbackAdditionalInfo.ulType == PLCH_SCAN_NETWORK_CALLBACK)
{
pNodeInfo = CallbackAdditionalInfo.AddInf.pNodeInfo;
if (pNodeInfo->lResult == RESULT_OK)
{
vList.push_back(*pNodeInfo);
bScanComplete = false;
}
else
{
pNodeInfoList = &vList[0]; //New pointer points to the vector elements, which will be used as an array later on
// I have also tried copying it, to the same result:
//std::copy(vList.begin(), vList.end(), pNodeInfoList);
bScanComplete = true;
}
}
}
return RESULT_OK;
}
So basically, the Notify method in the class above is called every time a "node" is found in the network, assigning the node's information to pNodeInfo (please disregard what a node is, it isn't relevant ATM). Since it is called to every node in the network during the scanning process and I must send this information to C++, I couldn't find any other way to do so other than using a std::vector to store every callback info for latter use, as I don't know how many nodes there will be at compile time. The else part is called after all nodes have been found. In order to make sense out of the C# code, I must describe the implementation of some other C++ methods that are p/Invoked:
PROASADLL __declspec(dllexport) void scanNetwork(){
pScanHandler->ScanNetwork(NULL, &scanNetworkCallback);
}
The object scanNetworkCallback is static. pScanHandler is a pointer to another class from the 3rd party vendor and its ScanNetwork method runs on a separate thread. Internally (and I only know that due to this API Guidelines, I don't have its source code), it calls the Notify method whenever a node is found in the network, or something to that effect
And finally:
PROASADLL __declspec(dllexport) NodeInfotyp* getScanResult(int* piSize) {
*piSize = scanNetworkCallback.vList.size();
return scanNetworkCallback.pNodeInfoList;
}
That returns the pointer that points to all nodes' information and the amount in as an out parameter. Now let's take a look at the C# code:
public static List<NodeInfoTag> AsaScanNetworkAsync()
{
Console.WriteLine("SCANNING NETWORK");
scanNetwork(); // C++ Method
while (!isScanComplete()) // Holds the C# thread until the scan is complete
Thread.Sleep(50);
int size = 0;
IntPtr pointer = getScanResult(out size); // works fine, I get some IntPtr and the correct size
List<NodeInfoTag> list = Marshaller.MarshalPointerToList<NodeInfoTag>(pointer, size); // PROBLEM!!!
// Continue doing stuff
}
This is the class NodeInfoTag, to match the C++ NodeInfotyp struct:
[StructLayout(LayoutKind.Sequential)]
public class NodeInfoTag
{
public int Result;
public int Complete;
[MarshalAs(UnmanagedType.LPStr)] //char*
public string NodeAddress;
[MarshalAs(UnmanagedType.LPStr)] //char*
public string ParentAddress;
[MarshalAs(UnmanagedType.LPWStr)] //wchar_t
public string VendorName;
public uint TargetType;
public uint TargetId;
public uint TargetVersion;
public short MaxChannels;
}
And this is where I get my Memory Access Violation:
internal class Marshaller
{
public static List<T> MarshalPointerToList<T>(IntPtr pointer, int size)
{
if (size == 0)
return null;
List<T> list = new List<T>();
var symbolSize = Marshal.SizeOf(typeof(T));
for (int i = 0; i < size; i++)
{
var current = (T)Marshal.PtrToStructure(pointer, typeof(T));
list.Add(current);
pointer = new IntPtr(pointer.ToInt32() + symbolSize);
}
return list;
}
}
The error occurs specifically when marshaling should take place, at the line var current = (T)Marshal.PtrToStructure(pointer, typeof(T));. This C# code used to work just fine, but the C++ part was terrible, convoluted and error-prone, so I decided to make things more simple but I can't figure out for the life of me why I'm getting this Exception as I'm making sure that all C++ resources are available for C#, since for testing purposes, I don't delete anything in C++ and I'm only using variables with global scope within the class, which is allocated to static memory. So, what did I miss?
Edit: I removed pNodeInfoList = &vList[0]; and rewrote getScanResult as follows:
static NodeInfotyp pNodeInfoList;
//(...)
PROASADLL __declspec(dllexport) NodeInfotyp* getScanResult(int* piSize) {
*piSize = scanNetworkCallback.vList.size();
std::move(scanNetworkCallback.vList.begin(),
scanNetworkCallback.vList.end(), &pNodeInfoList);
return &pNodeInfoList;
}
No dice. I don't use new or malloc in any of the variables involved, and even changed pNodeInfoList (the array) from a class member to a global variable. Also, I'm using move, as I've been told, could be used to solve ownership problems. Any other tips?
Ownership is not part of the naive C++ type system, so you will not get an error when you delete a pointer you do not own or transfer ownership away without giving it up.
However, semantically certain values and pointers and data blocks are owned by certain types or values.
In this case the vector owns its block of memory. There is no way to ask it or make it give up ownership.
Calling .data() onky provides you a pointer, it does not give that pointer semantic ownership.
You store the return value of .data() in a member variable. You later call delete on that member variable. This indicates to me that member variable is supposed to own its data. So you double delete (as both the vector and the pointer think they own the data pointed to), and your compiler crashes the program for you.
You need to rewite your code taking into account liefetime and ownership of every block of memory you are working with. One approach is to never ever call new, malloc or delete or free directly, and always use memory managing types like vector and unique ptr. Avoid persisting raw pointers, as their ownership semantics are not clear from the type.
So I have a number of different potential object that can output data (strings). What I want to be able to do, is to Run a generic Output.WriteLine function, with the potential arguments that define where you want it to be outputted to. What I've got for code -
//Defined in static class Const
public enum Out : int { Debug = 0x01, Main = 0x02, Code = 0x04 };
static class Output
{
private static List<object> RetrieveOutputMechanisms(Const.Out output)
{
List<object> result = new List<object>();
#if DEBUG
if (bitmask(output, Const.Out.Debug))
result.Add(1);//Console); //I want to add Console here, but its static
#endif
if (bitmask(output, Const.Out.Main))
if (Program.mainForm != null)
result.Add(Program.mainForm.Box);
if (bitmask(output, Const.Out.Code))
if (Program.code!= null)
result.Add(Program.code.Box);
return result;
}
public static void WriteLine(Color color, string str, Const.Out output = Const.Out.Debug & Const.Out.Main)
{
Console.WriteLine(
List<object> writers = RetrieveOutputMechanisms(output);
foreach (object writer in writers)
writer.WriteLine(str, color);
}
}
The point of this, is that the output destinations are not always existent, as they are on forms that may or may not exist when these calls are called. So the idea is to determine which ones you're trying to print to, determine if it exists, add it to the list of things to be printed to, then loop through and print to all of them if they implement the "WriteLine" method.
The two problems that I've come across, are
That Console is a static class, and can't properly (as far as my knowledge goes) be added to the object list.
I don't know how I can assert that the objects in the list define WriteLine, and cast them to something that would apply to more than one base Type. Assuming I can get Console to work properly in this scheme, that would be the obvious problem, its not of the same base type as the actual Boxes, but also, if I had something that wasnt a Box, then it would be lovely to do something like
foreach (object writer in writers)
.WriteLine(str, color)
so that I wouldn't have to individually cast them.
The bigger reason that I don't simply WriteLine from the RetrieveOutputMechanisms function, is that I want this to cover more than just WriteLine, which means that I would need to copy the bitmask code to each function.
EDIT: I realise that adding public properties to Program is a bad idea, if you know how I can avoid it (the necessity coming from needing to be able to access any WriteLine-able form objects that come and go, from anywhere), by all means please elaborate.
One way would be to use an Action (a delegate) and store those in your List. This will work for Console and any other class as you can easily write a lambda (or a 2.0 delegate) to map your output variables to the right parameters in the called method. There will be no need for casting. It could work something like this:
(This assumes you are using C# 3.5 or later but you can do all this in anything from 2.0 and on using delegates)
static class Output
{
private static List<Action<string, Color>> RetrieveOutputMechanisms(Const.Out output)
{
List<Action<string, Color>> result = new List<string, Color>();
#if DEBUG
if (bitmask(output, Const.Out.Debug))
result.Add((s, c) => Console.WriteLine(s, c)); //I want to add Console here, but its static
#endif
if (bitmask(output, Const.Out.Main))
if (Program.mainForm != null)
result.Add((s, c) => Program.mainForm.Box.WriteLine(s, c));
if (bitmask(output, Const.Out.Code))
if (Program.code!= null)
result.Add((s, c) => Program.code.Box.WriteLine(s, c));
return result;
}
public static void WriteLine(Color color, string str, Const.Out output = Const.Out.Debug & Const.Out.Main)
{
var writers = RetrieveOutputMechanisms(output);
foreach (var writer in writers)
writer(str, color);
}
}
(edit to add)
You could change this more significantly to allow classes to "register" to be able to do the writing for a specific "output mechanism" in the Output class itself. You could make Output a singleton (there are arguments against doing that but it would be better than sticking public static variables in your main program for this purpose). Here is an example with more significant changes to your original class:
public sealed class Output
{
private Dictionary<Out, Action<string, Color>> registeredWriters = new Dictionary<Out, Action<string, Color>>();
public static readonly Output Instance = new Output();
private void Output() { } // Empty private constructor so another instance cannot be created.
public void Unregister(Out outType)
{
if (registeredWriters.ContainsKey(outType))
registeredWriters.Remove(outType);
}
// Assumes caller will not combine the flags for outType here
public void Register(Out outType, Action<string, Color> writer)
{
if (writer == null)
throw new ArgumentNullException("writer");
if (registeredWriters.ContainsKey(outType))
{
// You could throw an exception, such as InvalidOperationException if you don't want to
// allow a different writer assigned once one has already been.
registeredWriters[outType] = writer;
}
else
{
registeredWriters.Add(outType, writer);
}
}
public void WriteLine(Color color, string str, Const.Out output = Const.Out.Debug & Const.Out.Main)
{
bool includeDebug = false;
#if DEBUG
includeDebug = true;
#endif
foreach (var outType in registeredWriters.Keys)
{
if (outType == Const.Out.Debug && !includeDebug)
continue;
if (bitmask(output, outType))
registeredWriters[outType](str, color);
}
}
}
Then elsewhere in your program, such as in the form class, to register a writer, do:
Output.Instance.Register(Const.Out.Main, (s, c) => this.Box.WriteLine(s, c));
When your form is unloaded you can then do:
Output.Instance.Unregister(Const.Out.Main);
Then another way would be to not use a singleton. You could then have more than one Output instance for different purposes and then inject these into your other classes. For instance, change the constructor for your main form to accept an Output parameter and store this is an object variable for later use. The main form could then pass this on to a child form that also needs it.
If your objects that have data that need to be written behave like this:
A always writes to console and log
B always writes to log
C always writes to console
For all data, then your best bet would be to declare an interface and have each of them implement the interface method for output. Then, in your calling code, declare them not as their actual types but instead of type IOutput or whatever interface u call that has the method. Then have two helper methods, one for actually outputting to console and one for actually outputting to a log file. A would call both helpers, B and C their respective ones.
If, on the other hand, your objects will write to various logs at differing times:
A, B and C sometimes write to console and sometimes to log, depending on some property
Then I would recommend you create an event handler for when a class wants something to be written. Then, have the logic that discerns what writes to console and what writes to log in a listener class and attach the appropriate ones to that output event. That way, you can keep the logic about what is being written to where in classes that encapsulate just that functionality, while leaving the A, B and C classes free of dependencies that may come to bite you down the road. Consider having a monolithic method as you describe which uses a bitmask. As soon as the behavior of A, B or C's logging changes, or if you need to add a new output, you suddenly need to worry about one class or method affecting all of them at once. This makes it less maintainable, and also trickier to test for bugs.
MethodInfo methodname = typeof(object).GetMethod("MethodA");
Then just use a if statement to check if methodname is null or not.
Suppose i am having a class
Class ABC
{
public string Method1()
{
return "a";
}
public string Method2()
{
return "b";
}
public string Method3()
{
return "c";
}
}
and Now i am calling this methods in two ways like :
ABC obj=new ABC();
Response.Write(obj.Method1());
Response.Write(obj.Method2());
Another way
Response.Write(new ABC().Method1());
Response.Write(new ABC().Method2());
The output will be same for above two method .
Can some please help me understanding the difference between obj.Method1() and new ABC().Method1()
Thanks in Advance..
obj and new ABC() are separate instances. In your example the output is the same because there is no instance-level data to show.
Try this to see the difference:
Class ABC
{
public string Name = "default";
public string Method1()
{
return "a";
}
}
then use the code below to show the difference with instance-level data:
ABC obj=new ABC();
obj.Name = "NewObject";
Response.Write(obj.Method1());
Response.Write(obj.Name);
Response.Write(new ABC().Method1());
Response.Write(new ABC().Name);
What #d-stanley is trying to say is that you allocate memory on creation that is is very valuable resource.
And the more complete answer is this: Classes created with some logic in mind. Although is perfectly workable Response.Write(new ABC().Method1()); but this is very short function and not as much useless... When you design class you implemented some logic boundary functionality and properties. For example FileStream has a inner property of Stream and make it accessible via various properties and you could set it in overloaded Open() method and destroy it in Dispose() method. And for example another class BinaryReader implements Stream also but threat it differently. From your logic you could implement all functions on single class - some MotherOfAllFunctions class the implements all the functions of FileStream and BinaryReader - but it's not a way of doing it.
Another point: In most of the cases some (or huge) ammount of memory is taken to initialize some internal logic of the class - for example SqlConnection class. Then you call Open() or any other method to call a database - there's some very powerful mechanics is thrown kick-in to support state machine initialization, managed-to-unmanagment calls and a lot of code could be executed.
Actually what you doing in any new SomeCLass().SomeMethod<int>(ref AnotherObject) is:
Response.Write(
var tmpABC = new ABC(); // Constructor call . Executed always (may throw)
string result = tmpABC.Method1(); // Or whatever could be casted to `string`
tmpABC.Dispose(); // GC will kick-in and try to free memory
return result;
);
As you see - this is the same code as if you have written it in this way. So what happens here is a lot of memory allocations and almost immediately all this valuable memory is thrown away. It makes more sense to initialize ABC() class and all it functionality power once and then use it everywhere so minimize memory over allocation. For example - it doesn't make any sense to open SqlConnection function in every function call in your DAL class the then immediately close it - better declare local variable and keep it alive - some fully initialized classes live as long as application thread process exist. So in case of this code style:
public class Program
{
private static FileStream streamToLogFile = new FileStream(...);
public int Main(string [] args)
{
new Run(new Form1(streamToLogFile));
}
}
In this logic - there's no need to keep class Form1 and I created it inline but all the functions the need to access FileStream object (valuable resource !) will access the same instance that been initialized only once.
Long story short
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 FirstObject type to SecondObject and continue to use it's properties and methods?
I've total control over FirstObject, but SecondObject is sealed and totally out of my scope!
May I achieve this through reflection? How? What do you think of the work that it might take to do it? Obviously both class can be a LOT more complex than the example above.
Both class can have templates like FirstObject<T> and SecondObject<T> which is intimidating me to use reflection for such a task!
Problem in reality
I've tried to state my problem the easier way for the sake of simplicity and to try to extract some knowledge to solve it but, by looking to the answers, it seems obvious to me that, to help me, you need to understand my real problem because changing object type is only the tip of the iceberg.
I'm developing a Workflow Definition API. The main objective is to have a API able to be reusable on top of any engine I might want to use(CLR through WF4, NetBPM, etc.).
By now I'm writing the middle layer to translate that API to WF4 to run workflows through the CLR.
What I've already accomplished
The API concept, at this stage, is somehow similar to WF4 with ActivityStates with In/Out Arguments and Data(Variables) running through the ActivityStates using their arguments.
Very simplified API in pseudo-code:
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 to translate this to WF4 was too run through the ActivitiesStates graph and do a somehow direct assignment of properties, using reflection where needed.
Again simplified pseudo-code, 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 would have an executable System.Activities.Activity object. I've already accomplished this easily.
The big issue
A big issue with this approach appeared when I began the Data object to System.Activities.Variable translation. The problem is WF4 separates the workflow execution from the context. Because of that both Arguments and Variables are LocationReferences that must be accessed through var.Get(context) function for the engine to know where they are at runtime.
Something like this is easily accomplished using 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() {
//Name = "WriteActivity2",
Text=new InArgument<string>(
context =>
String.Format("Int value: {0}", var2.Get(context)))
}
}
};
but if I want to represent 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 // <-- BIG PROBLEM !!
},
new Write() {
DescriptiveName="WriteActivity2",
Text="Int value: "+Convert.ToInt32(var2) // ANOTHER BIG PROBLEM !!
}
}
};
I end up with a BIG PROBLEM when using Data objects as Variables. I really don't know how to allow the developer, using my API, to use Data objects wherever who wants(just like in WF4) and later translate that Data to System.Activities.Variable.
Solutions come to mind
If you now understand my problem, the FirstObject and SecondObject are the Data and System.Activities.Variable respectively. Like I said translate Data to Variable is just the tip of the iceberg because I might use Data.Get() in my code and don't know how to translate it to Variable.Get(context) while doing the translation.
Solutions that I've tried or thought of:
Solution 1
Instead of a direct translation of properties I would develop NativeActivites for each flow-control activity(If, Sequence, Switch, ...) and make use of CacheMetadata() function to specify Arguments and Variables. The problem remains because they are both accessed through var.Get(context).
Solution 2
Give my Data class its own Get() function. It would be only an abstract method, without logic inside that it would, somehow, translate to Get() function of System.Activities.Variable. Is this even possible using C#? Guess not! Another problem is that a Variable.Get() has one parameter.
Solution 3
The worst solution that I thought of was CIL-manipulation. Try to replace the code where Data/Argument is used with Variable/Argument code. This smells like a nightmare to me. I know next to nothing about System.reflection.Emit and even if I learn it my guess is that it would take ages ... and might not even be possible to do it.
Sorry if I ended up introducing a bigger problem but I'm really stuck here and desperately needing a tip/path to go on.
This is called "duck typing" (if it looks like a duck and quacks like a duck you can call methods on it as though it really were a duck). Declare myObject as dynamic instead of as a specific type and you should then be good to go.
EDIT: to be clear, this requires .NET 4.0
dynamic myObject = new FirstObject();
// do stuff
myObject = new SecondObject();
// do stuff again
Reflection isn't necessarily the right task for this. If SecondObject is out of your control, your best option is likely to just make an extension method that instantiates a new copy of it and copies across the data, property by property.
You could use reflection for the copying process, and work that way, but that is really a separate issue.