C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
They are used as parameters in methods—this influences the time required to call a method. We test struct parameters. We decide if this is an effective coding technique.
Example. First, here are two type declarations. The first declaration is a struct type, which by definition inherits from the System.ValueType object. Internally, the struct has only one physical unit, containing two reference values.
And: Second, you can see the class declared, which contains two reference value members.
Tip: When used, the two types will be stored in different memory locations (stack and heap).
Example type declarations: C# struct ExampleStruct { public int[] _value1; public int[] _value2; public ExampleStruct(int[] value1, int[] value2) { this._value1 = value1; this._value2 = value2; } } class ExampleClass { public int[] _value1; public int[] _value2; public ExampleClass(int[] value1, int[] value2) { this._value1 = value1; this._value2 = value2; } }
Example 2. We can use the struct as a parameter. Here we create an array that is stored as a field in both the struct and class instances. The MethodStruct function receives a struct parameter. The MethodClass function receives a class parameter.
C# program that uses struct and class parameters using System; class Program { static int MethodStruct(ExampleStruct example) { return example._value1[0]; } static int MethodClass(ExampleClass example) { return example._value1[0]; } static void Main() { // // Create a new array with value 5. // int[] array1 = new int[1]; array1[0] = 5; Console.WriteLine("--- Array element assigned ---"); // // Create new struct and class. // ExampleStruct example1 = new ExampleStruct(array1, array1); ExampleClass example2 = new ExampleClass(array1, array1); // // Use struct and then class in method as parameters. // int value1 = MethodStruct(example1); Console.WriteLine(value1); int value2 = MethodClass(example2); Console.WriteLine(value2); // // Change the value of the array element. // array1[0] = 10; Console.WriteLine("--- Array element changed ---"); int value3 = MethodStruct(example1); Console.WriteLine(value3); int value4 = MethodClass(example2); Console.WriteLine(value4); } } Output --- Array element assigned --- 5 5 --- Array element changed --- 10 10
MethodStruct. This method receives a strongly-typed value of ExampleStruct type. When you call this method, the struct and all its fields will be physically copied onto the function stack.
And: The runtime can take significant time to copy structs when used as method parameters or even locals.
MethodClass receives a strongly-typed value containing a reference to an ExampleClass object. In the C# language, an object is the actual data. A reference is the variable that points to that data. The parameter here is a reference.
Tip: Reference values are basically pointers and are very lightweight and efficient. Instantiating objects is more expensive.
Benchmark. For the benchmark, we test the Dictionary class's TryGetValue method. When you call methods on a collection like Dictionary, at least one set of parameters will be copied. Large value types such as structs can slow down method calls.
Data types tested: C# struct A { public int[] a; public int[] b; } class B { public int[] a; public int[] b; } Dictionary used to store objects: C# var d1 = new Dictionary<string, A>(); var d2 = new Dictionary<string, B>(); d1.Add("a", new A()); d2.Add("a", new B()); Code tested in loop: C# A a1; if (d1.TryGetValue("a", out a1)) { var x = a1.a; } B b1; if (d2.TryGetValue("a", out b1)) { var x = b1.a; } Benchmark results 100000000 iterations tested. Also tested in reverse order (class then struct). A) Struct used: 3721 ms B) Class used: 3595 ms [faster]
We find that the performance of using structs as parameters continues to degrade with three and four fields. The class parameter, because it does not become larger, does not degrade as much.
And: This means that when the struct increases the number of fields, each method call such as TryGetValue becomes more expensive.
3 fields Struct: 3907 ms Class: 3733 ms 4 fields Struct: 4803 ms Class: 3634 ms
Discussion. A common optimization you can do with structs in your programs is to remove them and turn them into classes. When developing complex programs, you will usually extract methods. When you call methods with structs, performance degrades.
Tip: I recommend only using structs when the design of your application is complete.
And: Before adding custom structs, be sure to perform benchmarking that proves structs are beneficial.
Summary. Structs and classes can be used as parameters in C# programs. We noted how structs are implemented when you use them as parameters, reviewing value types. We also saw a benchmark of how structs perform in methods.