I have several input structures which I need to convert to some other structure so I can pass it to my method.
struct Source1
{
public float x1;
public float x2;
public float x3;
}
struct Source2
{
public float x1;
public float x3;
public float x2;
public float x4;
}
struct Target
{
public float x1;
public float x2;
public float x3;
}
I am sure that source structure has required field (type and name is what matters) but that field's offset is unknown. Also source structure might contain some extra fields that I don't need.
How do I copy required fields from source structure to target structure. I need to do it as fast as possible.
In C there is a very simple recipe for that kind of problems.
#define COPY(x, y) \
{\
x.x1 = y.x1;\
x.x2 = y.x2;\
x.x3 = y.x3;\
}
I was thinking about getting a collection of fields and then get field's value using its name as a key but it looks like slow solution to me.
Have a squiz at https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-implement-user-defined-conversions-between-structs .
It details the use of implicit operators which are one approach to consider.
Some example code:
using System;
namespace Test
{
struct Source1
{
public float x1;
public float x2;
public float x3;
public static implicit operator Target(Source1 value)
{
return new Target() { x1 = value.x1, x2 = value.x2, x3 = value.x3 };
}
}
struct Target
{
public float x1;
public float x2;
public float x3;
}
public class Program
{
static void Main(string[] args)
{
var source = new Source1() { x1 = 1, x2 = 2, x3 = 3 };
Target target = source;
Console.WriteLine(target.x2);
Console.ReadLine();
}
}
}
Another alternative is using AutoMapper. Performance will be slower though.
Look at this explicit cast
This is the source struct.
public struct Source
{
public int X1;
public int X2;
}
This is the target.
public struct Target
{
public int Y1;
public int Y2;
public int Y3;
public static explicit operator Target(Source source)
{
return new Target
{
Y1 = source.X1,
Y2 = source.X2,
Y3 = 0
};
}
}
Converting phase :
static void Main(string[] args)
{
var source = new Source {X1 = 1, X2 = 2};
var target = (Target) source;
Console.WriteLine("Y1:{0} ,Y2{1} ,Y3:{2} ",target.Y1,target.Y2,target.Y3);
Console.Read();
}
Related
I've been benchmarking some C# struct creation, and I've been surprised to find that creation of a nested struct is significantly slower than the un-nested version. I would have expected the JITter to basically produce the same assembly for a flat and nested structure, but this appears to not be the case.
Does anyone have an explanation for why the struct construction in my test code below doesn't get optimized down to just writing the 3 doubles? It seems to (if I'm reading the assembly correctly) zero and create a temporary memory location before writing the values to the final location - presumably actually creating a temporary copy of the nested struct.
And in the follow-up, is there a way to avoid this extra work such that the nested struct has similar creation speed to the un-nested one?
public class StructBenchmarks
{
public struct Vector3_dp
{
public Vector3_dp(double x, double y, double z)
{
X = x;
Y = y;
Z = z;
}
public double X;
public double Y;
public double Z;
}
public readonly struct ContainsVector
{
public ContainsVector(double x, double y, double z)
{
m_vector = new Vector3_dp(x, y, z);
}
public ContainsVector(Vector3_dp input)
{
m_vector = input;
}
private readonly Vector3_dp m_vector;
}
private ContainsVector m_vector1;
private ContainsVector m_vector2;
private Vector3_dp m_vector3_dp1;
private Vector3_dp m_vector3_dp2;
// 0.2ns
public void Vector3_dp_Construction()
{
m_vector3_dp1 = new Vector3_dp(20, 30, 40);
}
// 3.8ns
public void Vector_Construction()
{
m_vector1 = new ContainsVector(20, 30, 40);
}
// 3.8ns
public void Vector_ConstructionFromVector3_dp()
{
m_vector1 = new ContainsVector(m_vector3_dp1);
}
// ~0ns
public void Vector3_dp_Copy()
{
m_vector3_dp1 = m_vector3_dp2;
}
// ~0ns
public void Vector_Copy()
{
m_vector1 = m_vector2;
}
}
And SharpLab link: https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8BYAKAAJLyABAZhoCZyBlDKAVzAwCEYA7MAAt82KAGtcZKuQDeU6VTrlcbThnIA1GF2i0A+gBMADvIWzTZxfS06o+4wAoDEdsAA2McgjTlnrj+QAnj5+7p4AXgCUFpbmFLGWABrkALxeANwxCZQAmqlBmfHZ0gBa+eGFxeQAvmRZZkqhAYmVxY0uYeQ5rdnt/p4lPQq1pPU09LDYznxugcqqXOQAwhB8GNgAlny4NhjQY3JFCUora5vbu9BOHQHevjeewff95FFj0odV0vh6AG7aeyg+T4MAA7poAbpDEYHHcnlEhrERu8rMtVustjtIVAHJc7NDyFsjOwMNEjrFPl9KD9/rZ8kSSYjLMjyZYjFANr9sBhPJNprMIbZ7EZyDTsUzKCzYuzOdzPKcMRdsaK/tiAIwS8gyrk8tFnTF4lW0wEMQpjbVywWA4VG7HCjXmjk6zx4m1ioXQ011VmUAD0vvIAAYAHQMbZjJTUFBWqHGPSnFQcLgbVYOMkUlHU1Ue4xq4FgmP4xwMQM+Wil8goQORTVSyz+8i0YMADnDPvGNGjePjq0TahTfDTB0zttsebSIPBCvOWNsDhLZYrVZrYzrZgbTdbknbka72J72wWGAHADEoBB8K7oUP25Tsu7AePyJO9YrZ4CHA/Y0Y1Sv22uFF3QthR7IxAhvDN22+bNrWhJ8vyLIwvX/MYI3oKNC1A8D00sO8EgQ+CYOgZCkQsEYgA=
I guess, it's a pretty basic problem, but I couldn't find an answer.
Program is made for learning purpose, I'd defined a vector class with multiplication operator like this:
public class vector
{
private int x;
private int y;
public vector(int x,int y)
{
this.x = x;
this.y = y;
}
public static vector operator *(vector w1, vector w2)
{
return int w1.x*w2.x + w1.y * w2.y;
}
}
The problem is that visual studio underlines the expression in return, how should I modify the definition of "*" operator to make it work ?
You defined your function to return a vector, however you are only returning an int.
public static vector operator *(vector w1, vector w2)
{
return int w1.x*w2.x + w1.y * w2.y;
}
should be
public static int operator *(vector w1, vector w2)
{
return int (w1.x*w2.x + w1.y * w2.y);
}
Or for example, if you wanted to return a vector for the addition operator, that would look like:
public static vector operator +(vector w1, vector w2)
{
return new vector (w1.x+w2.x, w1.y + w2.y);
}
You need to return a new instance of vector, try this:
public class vector
{
private int x;
private int y;
public vector(int x, int y)
{
this.x = x;
this.y = y;
}
public static vector operator *(vector w1, vector w2)
{
return new vector(w1.x* w2.x, w1.y * w2.y);
}
}
Currently working on creating a VR head tracking using Wii remotes have faced a error.
The class *** can be designed, but is not the first class in the file.Visual Studio requires that designers use the first class in the file. Move the class code so that it is the first class in the file and try loading the designer again.
I have split the code in different pages however I receive the same error. This is the code I'm working on:
namespace WiiDesktopVR
{
class Point2D
{
public float x = 0.0f;
public float y = 0.0f;
public void set(float x, float y)
{
this.x = x;
this.y = y;
}
}
public class WiiDesktopVR : Form
{
struct Vertex
{
float x, y, z;
float tu, tv;
public Vertex(float _x, float _y, float _z, float _tu, float _tv)
{
x = _x; y = _y; z = _z;
tu = _tu; tv = _tv;
}
public static readonly VertexFormats FVF_Flags = VertexFormats.Position | VertexFormats.Texture1;
};
Vertex[] targetVertices =
{
new Vertex(-1.0f, 1.0f,.0f, 0.0f,0.0f ),
new Vertex( 1.0f, 1.0f,.0f, 1.0f,0.0f ),
new Vertex(-1.0f,-1.0f,.0f, 0.0f,1.0f ),
new Vertex( 1.0f,-1.0f,.0f, 1.0f,1.0f ),
};
}
}
Thanks
Move Point2D to the bottom of the file. Best practices state you should have only one class per file, so taking Stuart's advice and moving it to another file would be best.
namespace WiiDesktopVR
{
public class WiiDesktopVR : Form
{
struct Vertex
{
float x, y, z;
float tu, tv;
public Vertex(float _x, float _y, float _z, float _tu, float _tv)
{
x = _x; y = _y; z = _z;
tu = _tu; tv = _tv;
}
public static readonly VertexFormats FVF_Flags = VertexFormats.Position | VertexFormats.Texture1;
};
Vertex[] targetVertices =
{
new Vertex(-1.0f, 1.0f,.0f, 0.0f,0.0f ),
new Vertex( 1.0f, 1.0f,.0f, 1.0f,0.0f ),
new Vertex(-1.0f,-1.0f,.0f, 0.0f,1.0f ),
new Vertex( 1.0f,-1.0f,.0f, 1.0f,1.0f ),
};
}
class Point2D
{
public float x = 0.0f;
public float y = 0.0f;
public void set(float x, float y)
{
this.x = x;
this.y = y;
}
}
}
Ok,
It is not possible to store a struct instance inside a struct of the same type. So can anyone help me find a workaround please?
I need to store a vector3 inside a vector3 like this:
public struct Vector3{
float x,y,z;
Vector3 normalized;
}
Obviously, it creates an endless cycle as one would create a new one that creates a new one and so on...
So how would one do that? I would need my normalized to be a Vector3 since it needs to be recognized as such and cannot be any other naming.
Finally, I know this can be achieved with classes but I would not want.
Thanks
Well, a struct is a value type. Declaring a recursive struct would create an infinitely big struct! A workaround would be to declare it as class instead. But here I would simply declare Normalized as a property.
public struct Vector3 {
public Vector3(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
public float X { get; private set; }
public float Y { get; private set; }
public float Z { get; private set; }
public float Length {
get { return (float)Math.Sqrt(X * X + Y * Y + Z * Z); }
}
Vector3 Normalized {
get {
float l = Length;
return new Vector3(X / l, Y / l, Z / l);
}
}
}
You cannot store a struct of type X inside a struct of type X. However, you probably don't want to do this anyway, because in general, structs (and classes, for that matter) should only store the data they need to be complete. Instead, you can have a function that builds and returns the 'normalized' version of the struct:
public struct Vector3
{
float x,y,z;
public Vector3 Normalized
{
get
{
... build the normalized struct and return it ...
}
}
}
I have to call a C++ dll in C#. And the header of the dll is as following(simplified):
//Header of C++
struct vector
{
float x;
float y;
vector()
{}
vector(float x0, float y0)
{
x = x0;
y = y0;
}
};
struct unmanaged_struct
{
int int_var;
float float_var;
char* chars_var;
vector vector_var;
unmanaged_struct(int i, float f, char* ch, float vec_x, float vec_y)
{
int_var = i;
float_var = f;
chars_var = ch;
vector_var = vector(vec_x, vec_y);
}
};
// this function is used to output all the variable values of the struct instance
extern "C" __declspec( dllexport ) void unmanagedstruct_summary(unmanaged_struct* us_list, int length);
And I defined following class in C#
//CSharp
[StructLayout(LayoutKind.Sequential)]
public class Vector
{
public float x;
public float y;
public Vector(float f1, float f2)
{
x = f1;
y = f2;
}
}
[StructLayout(LayoutKind.Sequential)]
public class UnmanagedStruct
{
public int int_var;
public float float_var;
public string char_var;
public Vector vector_var;
public UnmanagedStruct(int i, float f, string s, Vector vec)
{
this.int_var = i;
this.float_var = f;
this.char_var = s;
this.vector_var = vec;
}
}
class UnmanagedDllCallTest
{
[DllImport("unmanageddll.dll", EntryPoint = "unmanagedstruct_summary")]
public static extern void unmanagedstruct_summary([Out]UnmanagedStruct[] usList, int length);
static void Main(string[] args)
{
UnmanagedStruct[] usList = new UnmanagedStruct[1];
usList[0] = new UnmanagedStruct(1, 1.0f, "aa", new Vector(10, 1));
usList[1] = new UnmanagedStruct(2, 2.0f, "ba", new Vector(20, 2));
UnmanagedDllCallTest.unmanagedstruct_summary(usList, 2);
}
And the output is as following:
unmanaged_struct summary:
0
1.12104e-044
Unhandled Exception:
System.AccessViolationException:
Attempted to read or write protected
memory. This is often an indication
that other memory is corrupt. at
callunmanageddll.UnmanagedDllCallTest.unmanagedstruct_summary(UnmanagedStr
uct[] usList, Int32 length) at
callunmanageddll.Program.Main(String[]
args) in c:\users\dynaturtle\docume
nts\visual studio
2010\Projects\callunmanageddll\callunmanageddll\Program.cs:lin
e 68
The C++ dll is OK as I have written test in C++ and the function works well. I have read this thread but it seems the solution didn't work in my case. Any suggestions? Thanks in advance!
Use Marshal.PtrToStructure. There is a sample here.
So you would have to change the signature of the method from out structure array to out IntPtr. However, you need to know the size of the buffer being passed out.
public struct Vector
{
public float x;
public float y;
}
public struct UnmanagedStruct
{
public int int_var;
public float float_var;
public string char_var;
public Vector vector_var;
}
class UnmanagedDllCallTest
{
[DllImport("unmanageddll.dll", EntryPoint = "unmanagedstruct_summary")]
public static extern void unmanagedstruct_summary([Out] IntPtr ptr, int length);
static void Main(string[] args)
{
for(int i=0; i<length; i++)
{
UnmanagedStruc st;
Marshal.PtrToStructure(ptr, st);
// increment ptr and move forward
}
}
First: Vector and UnmanagedStruct should be structs, not classes.
JIC I'd share my approach. Perhaps this is not an expected answer by at one time I spend a time to resolve my issue.
I have the following structure to expose some data from DLL.
//C++ code
struct State
{
const wchar_t * name;
unsigned int state;
};
APIENTRY bool get_states(H_PRCSR, MacroState *, const int sz); //pay attention, function accepts already allocated array and size for it
To accept this data From C++ I can do this way
std::vector<State> states(desired_size);
get_states(hparser, &states[0], states.size());
To do the same on C# I used the following way
//C#
[StructLayout(LayoutKind.Sequential)]
public struct Status
{
public IntPtr name;
public uint state;
public string getName()
{
if (name == IntPtr.Zero) return "<no-value>";
return Marshal.PtrToStringUni(name);
}
}
//And import function...
[DllImport(dll, CallingConvention = CallingConvention.Winapi)]
private static extern bool get_states(IntPtr p, [Out]MacroFlag[] flags, int flags_size);
//And simple decoder
public static Status[] getAll(IntPtr p, int size)
{
var results = new Status[size];
get_states(p, results, size);
return results;
}
As, I saw the are different approaches to do this. This is one of them. And it works for me. Perhaps, this post will not resolve the issue but will be a good point to start