reflection to read/write unmanaged data stucture

  • Thread starter Thread starter bill
  • Start date Start date
B

bill

All,

I have an unmanaged data structure that I use to pass to an umanaged
DLL written in C. This works great. The structure looks sort of like
this:

unsafe public struct Inputs
{
.....
[StructLayout(LayoutKind.Sequential)]
public struct InputA
{
public fixed double array1[3];
public double dt;
public fixed double array2[3];
}
.....
}

The unmanaged DLL is compiled as part of my Solution so there should be
a bunch of metadata laying around. I now know how to read a value from
a field in the structure thru reflection - more or less like this:

Inputs.InputA inp = new Inputs.InputA();
....
Type t = inp.GetType();
MemberInfo[] m = t.GetMembers();

// Find the index in m[] where the Field "dt" is located (not a
problem) - "9" in this example

Object dt = t.InvokeMember(m[9].Name, BindingFlags.GetField,
null, inp, null);

Wonderfully, dt contains the value from the inp structure. Now the
problem... I want to set the value of "dt" in the inp structure to
something else. I try the following:

Object[] newDT= new object[] { 2.777 };
t.InvokeMember(myMemberInfo[9].Name,
BindingFlags.DeclaredOnly | BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.Static |
BindingFlags.SetField, null, inp, newDT);

The value of "dt" in the inp structure does NOT change, and there is no
error message. Any suggestions greatfully received. Yes, I know that I
can access the structure directly. However, I REALLY DO have a good
reason to want to use reflection to do this.

TIA,

Bill
 
| All,
|
| I have an unmanaged data structure that I use to pass to an umanaged
| DLL written in C. This works great. The structure looks sort of like
| this:
|
| unsafe public struct Inputs
| {
| ....
| [StructLayout(LayoutKind.Sequential)]
| public struct InputA
| {
| public fixed double array1[3];
| public double dt;
| public fixed double array2[3];
| }
| ....
| }
|
| The unmanaged DLL is compiled as part of my Solution so there should be
| a bunch of metadata laying around. I now know how to read a value from
| a field in the structure thru reflection - more or less like this:
|
| Inputs.InputA inp = new Inputs.InputA();
| ...
| Type t = inp.GetType();
| MemberInfo[] m = t.GetMembers();
|
| // Find the index in m[] where the Field "dt" is located (not a
| problem) - "9" in this example
|
| Object dt = t.InvokeMember(m[9].Name, BindingFlags.GetField,
| null, inp, null);
|
| Wonderfully, dt contains the value from the inp structure. Now the
| problem... I want to set the value of "dt" in the inp structure to
| something else. I try the following:
|
| Object[] newDT= new object[] { 2.777 };
| t.InvokeMember(myMemberInfo[9].Name,
| BindingFlags.DeclaredOnly | BindingFlags.Public |
| BindingFlags.NonPublic |
| BindingFlags.Instance | BindingFlags.Static |
| BindingFlags.SetField, null, inp, newDT);
|
| The value of "dt" in the inp structure does NOT change, and there is no
| error message. Any suggestions greatfully received. Yes, I know that I
| can access the structure directly. However, I REALLY DO have a good
| reason to want to use reflection to do this.
|
| TIA,
|
| Bill
|

InvokeMember( , BindingFlags.SetField,..)
involves a boxing operation, you have to box the value type and pass the
boxed value to InvokeMember's target and unbox after the call.
Quite expensive, you must have very good reasons to do this.

Willy.
 
Willy Denoyette said:
| All,
|
| I have an unmanaged data structure that I use to pass to an umanaged
| DLL written in C. This works great. The structure looks sort of like
| this:
|
| unsafe public struct Inputs
| {
| ....
| [StructLayout(LayoutKind.Sequential)]
| public struct InputA
| {
| public fixed double array1[3];
| public double dt;
| public fixed double array2[3];
| }
| ....
| }
|
| The unmanaged DLL is compiled as part of my Solution so there should be
| a bunch of metadata laying around. I now know how to read a value from
| a field in the structure thru reflection - more or less like this:

That's not really an unmanaged structure, because you have metadata to
manage it. Maybe better to call it "explicit layout". The only kind of
"metadata" you can get for an unmanaged structure is the .pdb debug
database.
|
| Inputs.InputA inp = new Inputs.InputA();
| ...
| Type t = inp.GetType();
| MemberInfo[] m = t.GetMembers();
|
| // Find the index in m[] where the Field "dt" is located (not a
| problem) - "9" in this example
|
| Object dt = t.InvokeMember(m[9].Name, BindingFlags.GetField,
| null, inp, null);
|
| Wonderfully, dt contains the value from the inp structure. Now the
| problem... I want to set the value of "dt" in the inp structure to
| something else. I try the following:
|
| Object[] newDT= new object[] { 2.777 };
| t.InvokeMember(myMemberInfo[9].Name,
| BindingFlags.DeclaredOnly | BindingFlags.Public |
| BindingFlags.NonPublic |
| BindingFlags.Instance | BindingFlags.Static |
| BindingFlags.SetField, null, inp, newDT);
|
| The value of "dt" in the inp structure does NOT change, and there is no
| error message. Any suggestions greatfully received. Yes, I know that I
| can access the structure directly. However, I REALLY DO have a good
| reason to want to use reflection to do this.
|
| TIA,
|
| Bill
|

InvokeMember( , BindingFlags.SetField,..)
involves a boxing operation, you have to box the value type and pass the
boxed value to InvokeMember's target and unbox after the call.
Quite expensive, you must have very good reasons to do this.

More to the point, InvokeMember operates on the boxed copy, not the real
value. You need to keep a reference to the boxed copy:

object boxinp = inp;
InvokeMember(...inp...);

Now boxinp should be changed. You can set all the variables you want, then
at the end,
inp = (InputA)boxinp;
 
|
| | >
| > | > | All,
| > |
| > | I have an unmanaged data structure that I use to pass to an umanaged
| > | DLL written in C. This works great. The structure looks sort of like
| > | this:
| > |
| > | unsafe public struct Inputs
| > | {
| > | ....
| > | [StructLayout(LayoutKind.Sequential)]
| > | public struct InputA
| > | {
| > | public fixed double array1[3];
| > | public double dt;
| > | public fixed double array2[3];
| > | }
| > | ....
| > | }
| > |
| > | The unmanaged DLL is compiled as part of my Solution so there should
be
| > | a bunch of metadata laying around. I now know how to read a value from
| > | a field in the structure thru reflection - more or less like this:
|
| That's not really an unmanaged structure, because you have metadata to
| manage it. Maybe better to call it "explicit layout". The only kind of
| "metadata" you can get for an unmanaged structure is the .pdb debug
| database.
|
| > |
| > | Inputs.InputA inp = new Inputs.InputA();
| > | ...
| > | Type t = inp.GetType();
| > | MemberInfo[] m = t.GetMembers();
| > |
| > | // Find the index in m[] where the Field "dt" is located (not a
| > | problem) - "9" in this example
| > |
| > | Object dt = t.InvokeMember(m[9].Name, BindingFlags.GetField,
| > | null, inp, null);
| > |
| > | Wonderfully, dt contains the value from the inp structure. Now the
| > | problem... I want to set the value of "dt" in the inp structure to
| > | something else. I try the following:
| > |
| > | Object[] newDT= new object[] { 2.777 };
| > | t.InvokeMember(myMemberInfo[9].Name,
| > | BindingFlags.DeclaredOnly | BindingFlags.Public |
| > | BindingFlags.NonPublic |
| > | BindingFlags.Instance | BindingFlags.Static |
| > | BindingFlags.SetField, null, inp, newDT);
| > |
| > | The value of "dt" in the inp structure does NOT change, and there is
no
| > | error message. Any suggestions greatfully received. Yes, I know that I
| > | can access the structure directly. However, I REALLY DO have a good
| > | reason to want to use reflection to do this.
| > |
| > | TIA,
| > |
| > | Bill
| > |
| >
| > InvokeMember( , BindingFlags.SetField,..)
| > involves a boxing operation, you have to box the value type and pass the
| > boxed value to InvokeMember's target and unbox after the call.
| > Quite expensive, you must have very good reasons to do this.
|
| More to the point, InvokeMember operates on the boxed copy, not the real
| value.

Hmmm... where exactly did I say that it operates on the real value?
InvokeMember 'involves a boxing operation', that is, it implicitly boxes the
value type passed in as an argument, but after the call the "boxed" instance
vanishes waiting to be collected (it's no longer referenced) , so you must
box before calling an pass the boxed value to InvokeMember and unbox when
done.

like this:

object temp = new Inputs() as object;
typeof(Inputs).InvokeMember("i", BindingFlags.SetField , null, temp,
new object[] {1.23});
Inputs inp = (Inputs) so;

| You need to keep a reference to the boxed copy:
|
| object boxinp = inp;
| InvokeMember(...inp...);
|

small correction..... you need to pass the 'boxed' reference boxinp.

| Now boxinp should be changed. You can set all the variables you want,
then
| at the end,
| inp = (InputA)boxinp;
|
| >
| > Willy.
| >
| >

Willy.
 
Gentlemen,

Thanks so much, its works perfectly.

Bill

|
| | >
| > | > | All,
| > |
| > | I have an unmanaged data structure that I use to pass to an umanaged
| > | DLL written in C. This works great. The structure looks sort of like
| > | this:
| > |
| > | unsafe public struct Inputs
| > | {
| > | ....
| > | [StructLayout(LayoutKind.Sequential)]
| > | public struct InputA
| > | {
| > | public fixed double array1[3];
| > | public double dt;
| > | public fixed double array2[3];
| > | }
| > | ....
| > | }
| > |
| > | The unmanaged DLL is compiled as part of my Solution so there should
be
| > | a bunch of metadata laying around. I now know how to read a value from
| > | a field in the structure thru reflection - more or less like this:
|
| That's not really an unmanaged structure, because you have metadata to
| manage it. Maybe better to call it "explicit layout". The only kind of
| "metadata" you can get for an unmanaged structure is the .pdb debug
| database.
|
| > |
| > | Inputs.InputA inp = new Inputs.InputA();
| > | ...
| > | Type t = inp.GetType();
| > | MemberInfo[] m = t.GetMembers();
| > |
| > | // Find the index in m[] where the Field "dt" is located (not a
| > | problem) - "9" in this example
| > |
| > | Object dt = t.InvokeMember(m[9].Name, BindingFlags.GetField,
| > | null, inp, null);
| > |
| > | Wonderfully, dt contains the value from the inp structure. Now the
| > | problem... I want to set the value of "dt" in the inp structure to
| > | something else. I try the following:
| > |
| > | Object[] newDT= new object[] { 2.777 };
| > | t.InvokeMember(myMemberInfo[9].Name,
| > | BindingFlags.DeclaredOnly | BindingFlags.Public |
| > | BindingFlags.NonPublic |
| > | BindingFlags.Instance | BindingFlags.Static |
| > | BindingFlags.SetField, null, inp, newDT);
| > |
| > | The value of "dt" in the inp structure does NOT change, and there is
no
| > | error message. Any suggestions greatfully received. Yes, I know that I
| > | can access the structure directly. However, I REALLY DO have a good
| > | reason to want to use reflection to do this.
| > |
| > | TIA,
| > |
| > | Bill
| > |
| >
| > InvokeMember( , BindingFlags.SetField,..)
| > involves a boxing operation, you have to box the value type and pass the
| > boxed value to InvokeMember's target and unbox after the call.
| > Quite expensive, you must have very good reasons to do this.
|
| More to the point, InvokeMember operates on the boxed copy, not the real
| value.

Hmmm... where exactly did I say that it operates on the real value?
InvokeMember 'involves a boxing operation', that is, it implicitly boxes the
value type passed in as an argument, but after the call the "boxed" instance
vanishes waiting to be collected (it's no longer referenced) , so you must
box before calling an pass the boxed value to InvokeMember and unbox when
done.

like this:

object temp = new Inputs() as object;
typeof(Inputs).InvokeMember("i", BindingFlags.SetField , null, temp,
new object[] {1.23});
Inputs inp = (Inputs) so;

| You need to keep a reference to the boxed copy:
|
| object boxinp = inp;
| InvokeMember(...inp...);
|

small correction..... you need to pass the 'boxed' reference boxinp.

| Now boxinp should be changed. You can set all the variables you want,
then
| at the end,
| inp = (InputA)boxinp;
|
| >
| > Willy.
| >
| >

Willy.
 
| > InvokeMember( , BindingFlags.SetField,..)
| > involves a boxing operation, you have to box the value type and pass
the
| > boxed value to InvokeMember's target and unbox after the call.
| > Quite expensive, you must have very good reasons to do this.
|
| More to the point, InvokeMember operates on the boxed copy, not the real
| value.

Hmmm... where exactly did I say that it operates on the real value?
You didn't... now I see you were suggesting exactly the example code I
provided, but the first time I read through it, I thought you were
describing the compiler creating a temporary boxing variable.

I also think you were confusing the issue with "quite expensive". Boxing
and unboxing are more expensive than direct access, but so much faster than
the reflection invoke as to be lost in the noise.

I wasn't contradicting you, I was trying to provide a succinct summary with
example code.
 
|
| > | > InvokeMember( , BindingFlags.SetField,..)
| > | > involves a boxing operation, you have to box the value type and pass
| > the
| > | > boxed value to InvokeMember's target and unbox after the call.
| > | > Quite expensive, you must have very good reasons to do this.
| > |
| > | More to the point, InvokeMember operates on the boxed copy, not the
real
| > | value.
| >
| > Hmmm... where exactly did I say that it operates on the real value?
| You didn't... now I see you were suggesting exactly the example code I
| provided, but the first time I read through it, I thought you were
| describing the compiler creating a temporary boxing variable.
|
| I also think you were confusing the issue with "quite expensive". Boxing
| and unboxing are more expensive than direct access, but so much faster
than
| the reflection invoke as to be lost in the noise.
|
| I wasn't contradicting you, I was trying to provide a succinct summary
with
| example code.
|
|

Ben, Notice that the OP is using fixed buffers in it's structure, that means
that the data is in-lined, and moving such structure to and from the heap
can get quite costly (depending on the size of the buffers) this combined
with interop marshaling (which I guess the OP is using the struct for) may
have some negative inpact on performance.

Willy.
 
Back
Top