0

I have two predefined structs

Context // x86
Context64 // x64

I am trying to create an instance of one of these structs based on the process architecture. For example, if it was compiled as x86 it would create an instance of Context and if it was compiled as x64 it would create instance of Context64

I am having trouble forming a statement that will swap between the two instances based on what the program was compiled as

So far I have tried the following

var compiledAsx64 = Environment.Is64BitProcess;

var context = compiledAsx64 ? new Context64() : new Context();

And

var compiledAsx64 = Environment.Is64BitProcess;

dynamic context = compiledAsx64 ? new Context64() : new Context();

However, both return errors stating that there is no implicit conversion between the two

I am trying to avoid making multiple variables. Is this possible and if so how could I accomplish it?

  • What are `Context` and `Context64` structures, please? – Dmitry Bychenko Oct 18 '18 at 08:07
  • The only type of variable which could contain either would be `object`, and then you'll be constantly boxing/unboxing to work with it. If they were *classes*, then there may be some inheritance tricks. – Damien_The_Unbeliever Oct 18 '18 at 08:10
  • Question is not related with processor architecture at all. You trying to set variable to different types – Renatas M. Oct 18 '18 at 08:11
  • Depending on where you need this functionality you may just introduce a compiler-swicth, sth like `#IF x86 var a = Context #ELSE var a = Context64`. – MakePeaceGreatAgain Oct 18 '18 at 08:19
  • There is no single struct-typed variable that can hold values of both these types, you need to go for multiple variables or live with the consequence of boxing them into objects. For the latter you can go with interfaces, turning them into classes, or use dynamic, different choices, different performance characteristics. – Lasse V. Karlsen Oct 18 '18 at 08:21
  • If the "bit-specific" parts of the structs are isolated to one section (or they're all "int" vs "long", as an example), then you may be able to play some games with generics. – Damien_The_Unbeliever Oct 18 '18 at 08:21
  • An additional consequence of having multiple variables is that all your code *using* these structs also needs to be duplicated, I would seriously look into creating a common way of handling them using interfaces or similar. – Lasse V. Karlsen Oct 18 '18 at 08:22
  • I'm not entirely sure that would be possible. The contents of Context and Context64 can be found at this [link](https://www.pinvoke.net/default.aspx/kernel32/GetThreadContext.html). They are quite long which is why I intentional left them out of this post –  Oct 18 '18 at 08:23
  • Do you need to write lots of code using these? Can't you simply create 2 similar copies of some basic code that calls this function and then copies the data you need into a common type that you can then use for the rest of the code? – Lasse V. Karlsen Oct 18 '18 at 08:24
  • Theoretically, yes I could copy them into a common type (as I only really need the Instruction Pointer), however, I would still face the problem of determining if the process was compiled as x64 or x86 and calling the correct pinvoke call to fill the respective struct (as the structs are quite different between x86 and x64) Seems a bit like an unnecessary step –  Oct 18 '18 at 08:30

2 Answers2

1

Cast either one to the target type and you're good to go.

dynamic context = compiledAsx64 ? (dynamic)new Context64() : new Context();

Why? Per the documentation:

Either the type of first_expression and second_expression must be the same, or an implicit conversion must exist from one type to the other.

A better way to do this though is to use #if so you can have type safety. See this question: How to use #if to decide which platform is being compiled for. So your code would look like this:

#if X64
var context = new Context64();
#else
var context = new Context();
#endif
John Wu
  • 50,556
  • 8
  • 44
  • 80
  • The `#if X64` part will only be used during compilation, if you create an any-cpu application that can run as 64-bit on a 64-bit OS, and 32-bit on a 32-bit OS, you will still have made the choice of which struct to use at compile time, or you would have to deliver a 32-bit and a 64-bit copy of the application as well. – Lasse V. Karlsen Oct 18 '18 at 08:23
0

The compiler needs to determine a common type for the return of the conditional operator (?…:). That the result will be assigned to a dynamic makes no difference.

The simplest way to keep the conditional operator is likely to be both Context64 and Content implementing a common interface.

Even easier would be to use statements...

dynamic context;
if (Environment.Is64BitProcess) {
  context = new Context64();
} else {
  context = new Context();
}
Richard
  • 106,783
  • 21
  • 203
  • 265
  • Contexts are structs and I would not suggest to implement common interface just to use conditional operator. – Renatas M. Oct 18 '18 at 08:15
  • @Reniuz Don't forget `dynamic` is really `object` plus metadata and reflection: ie. far higher overhead. The "best" answer depends on what `Context`/`Context64` is used for. – Richard Oct 18 '18 at 08:18
  • Agree, it depends on use case. – Renatas M. Oct 18 '18 at 08:25