C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
Step 1: The struct is created on the stack. No "new" keyword is used. It is used like a value type such as int.
Step 2: We can access a field from a struct, in the same way that we can access a class field.
ClassInfo: The struct has the composite name "Program.Simple": it is nested within the Program class.
C# program that declares struct
using System;
class Program
{
struct Simple
{
public int Position;
public bool Exists;
public double LastValue;
};
static void Main()
{
// Step 1: create struct on stack.
Simple s;
s.Position = 1;
s.Exists = false;
s.LastValue = 5.5;
// Step 2: write struct field.
Console.WriteLine(s.Position);
}
}
Output
1
Step 1: We see that DateTime is a struct. We create a DateTime and then copy it into a separate DateTime variable.
Step 2: We print the values of the DateTime and its copy—the copy has all the same internal data as the original, but is separate.
Step 3: We change the original DateTime. Here the copy remains the same—it is kept separate.
C# program that uses DateTime struct
using System;
class Program
{
static void Main()
{
// Step 1: create Date Time and copy it.
DateTime date = new DateTime(2000, 1, 1);
DateTime dateCopy = date;
// Step 2: show struct values.
Console.WriteLine(date);
Console.WriteLine(dateCopy);
// Step 3: see that copy is not modified.
date = DateTime.MinValue;
Console.WriteLine(dateCopy);
}
}
Output
1/1/2000 12:00:00 AM
1/1/2000 12:00:00 AM
1/1/2000 12:00:00 AM
Tip: You can provide properties for the struct that simplify access to its data.
PropertyC# program that uses property on struct
using System;
class Program
{
static void Main()
{
// Initialize to 0.
S st = new S();
st.X = 5;
Console.WriteLine(st.X);
}
struct S
{
int _x;
public int X
{
get { return _x; }
set
{
if (value < 10)
{
_x = value;
}
}
}
};
}
Output
5
Part 1: We create a class instance by using the new keyword. We can then access its public fields X and Y.
NewPart 2: We create a struct. We don't have to instantiate a struct with the new keyword. We can directly access it.
Info: You cannot use a custom default constructor on structs, as when they are constructed, all fields are assigned to zero.
C# program that uses class and struct
using System;
class Program
{
class C
{
public int X;
public int Y;
}
struct CStruct
{
public int X;
public int Y;
}
static void Main()
{
// Part 1: use class.
C local = new C();
local.X = 1;
local.Y = 2;
Console.WriteLine("CLASS X: {0}", local.X);
// Part 2: use struct.
CStruct localStruct;
localStruct.X = 1;
localStruct.Y = 2;
Console.WriteLine("STRUCT X: {0}", localStruct.X);
}
}
Output
CLASS X: 1
STRUCT X: 1
And: Because DateTime itself is a struct, it will be stored directly in the struct allocation on the stack.
Thus: In a struct with two strings and a DateTime, the struct will hold two references and one value together.
Example: We replaced the class with a struct. This should improve performance by about two times and reduce memory.
C# program that uses struct in website
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
var _d = new Dictionary<string, ReferrerInfo>();
// New struct:
ReferrerInfo i;
i.OriginalString = "cat";
i.Target = "mat";
i.Time = DateTime.Now;
_d.Add("info", i);
}
/// <summary>
/// Contains information about referrers.
/// </summary>
struct ReferrerInfo
{
public string OriginalString; // Reference.
public string Target; // Reference.
public DateTime Time; // Value.
};
}
And: Structs were ideal here. There were over 500 instances of the object. And they only had two fields (both value types).
KeyValuePair: The .NET Framework provides the KeyValuePair struct for storing a pair. It is used internally in the Dictionary.
KeyValuePairAlso: It is worthwhile to use structs for graphics. When using graphics contexts, we use structs for points and coordinates.
C# program that uses Dictionary of structs
using System.Collections.Generic;
class Program
{
static void Main()
{
// Stores Dictionary of structs.
var _d = new Dictionary<string, FileData>();
FileData f;
f.Start = 1000;
f.Length = 200;
_d.Add("key", f);
}
/// <summary>
/// Stores where each blob is stored.
/// </summary>
struct FileData
{
public int Start;
public int Length;
}
}
Info: Using structs, CLRProfiler indicates that the List took 24 bytes and contained one object of 4.0 MB.
Tip: Structs are not stored as separate objects in arrays, but are grouped together. We see that structs consume less memory.
Class version:
Size of List: 1 object
512 KB
Size of internal array: 100000 objects
3.8 MB
Struct version:
Size of List: 1 object
24 bytes
Size of internal array: 1 object
4.0 MB
Version 1: In this version of the code, we allocate a class in a tight loop and compute the average amount of time required.
Version 2: Here we allocate a struct that has the same fields as the class. Each type has 8 fields.
Result: We see substantial speedups when allocating the structs. For pure allocation speed, structs are faster.
Important: Strings are reference types. Their internal data is not embedded in the struct—it just stores the reference.
C# program that times classes, structs
using System;
using System.Diagnostics;
class AllocateClass
{
public string A;
public string B;
public string C;
public string D;
public int E;
public int F;
public int G;
public int H;
}
struct AllocateStruct
{
public string A;
public string B;
public string C;
public string D;
public int E;
public int F;
public int G;
public int H;
}
class Program
{
const int _max = 10000000;
static void Main()
{
var s1 = Stopwatch.StartNew();
// Version 1: allocate class.
for (int i = 0; i < _max; i++)
{
AllocateClass test = new AllocateClass();
test.E = 10;
if (test.E != 10)
{
return;
}
}
s1.Stop();
var s2 = Stopwatch.StartNew();
// Version 2: allocate struct.
for (int i = 0; i < _max; i++)
{
AllocateStruct test;
test.E = 10;
if (test.E != 10)
{
return;
}
}
s2.Stop();
Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) /
_max).ToString("0.00 ns"));
Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) /
_max).ToString("0.00 ns"));
}
}
Output
4.28 ns Allocate class
0.98 ns Allocate struct
Tip: Heap allocation is used for the data of arrays and objects. Structs, meanwhile, have all their data stored inline.
Info: With structs you avoid the overhead of objects. This reduces memory pressure. And it (sometimes) improves performance.
Term: The term "value semantics" refers to how a struct has all its data inline, and is not stored in a separate location on the heap.
Tip: These types often make ideal structs. But even here, structs may make things worse (often because of parameter passing).
Note: Nullable types are a generic type that can be null. In complex programs these can help simplify code.
NullableHowever: Using structs can improve performance with the string reference itself. References are also data.
Tip: Pointers, like references, are values that contain the addresses of data. When used correctly, pointers are fast.
But: Their syntax and lack of error checking causes problems. They are harder to use than references.
Fixed buffers: The struct type can be used with fixed buffers as a memory region.
Fixed