I need to broaden my understanding of how structs are compiled when using generics.
I have the following code, which works
public struct TestStruct
{
public GenericStruct<SecondTestStruct> Header;
public int TestValue;
}
public struct GenericStruct<T>
{
public int MessageSize => System.Runtime.InteropServices.Marshal.SizeOf(typeof(T));
}
public struct SecondTestStruct
{
public int TestValue;
}
static void Main(string[] args)
{
TestStruct test = new TestStruct();
Console.WriteLine($"Size of test is: {test.Header.MessageSize}");
}
This prints 'Size of test is: 4'
However, if I change TestStruct to attempt to provide its own size:
public struct TestStruct
{
public GenericStruct<TestStruct> Header;
public int TestValue;
}
I get a runtime error: System.TypeLoadException: Could not load type 'TestStructGenerics.TestStruct' from assembly.
I'm guessing it has to do with the compiler being unable to create the struct compile time. Or perhaps a problem with circular references when handling the generic resolution.
EDIT:
I just realized that I can achieve what I want by changing the second case to:
public struct TestStruct
{
public GenericStruct<TestStruct> Header => new GenericStruct<TestStruct>();
public int TestValue;
}
According to Eric Lippert's comments in this Roslyn issue, it is unclear whether this problem is a CLR type loader limitation or whether programs of this sort are invalid, and, if they are invalid, whether the C# compiler should detect it and emit an error. Practically, it appears that, until the authorities decide, we have to avoid type loops between structs regardless of the mode that introduces dependence - instance field (that's never going to work because the struct would be infinite size), static field, implemented generic interface, or generic argument. One can break these struct type loops at compile time by changing some struct in the loop to a class, or at run time by going through object or interface and casting.
See also the corresponding CLR issue.
Related
Why would the inline instantiated struct suddenly become a managed type? Not only is its generic constrained to unmanaged, but the struct itself is fully blittable.
public struct MyStruct<T> where T : unmanaged
{
public int SomePrimitive;
}
public void DoSomething()
{
var mystruct = new MyStruct<int>();
var myPtr = &mystruct;
}
I was using C# 7.3 (Unity Compatibility). Apparently this exact thing became possible in C# 8.0
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#unmanaged-constructed-types
After looking at so many complicated questions related to this i want to ask the explanation for following code having static field initialization. one more thing i want to know is the requirement of static field initialization. In which scenarios it ll be helpful??
using System;
class Test
{
static void Main()
{
Console.WriteLine("{0} {1}", B.Y, A.X);
}
public static int F(string s)
{
Console.WriteLine(s);
return 1;
}
}
class A
{
static A()
{ }
public static int X = Test.F("Init A");
}
class B
{
static B()
{ }
public static int Y = Test.F("Init B");
}
Output:
Init B
Init A
1 1
When no static constructor is present then output may vary. I am not able to understand the rationale behind it.What difference static field initialization has brought to this fragment?. Can someone please help. I am a newb with c#.
When a type has a static constructor, the runtime is constrained to execute all type initialization immediately before the first use of any member of the type.
When it doesn't have a static constructor, the runtime has much more freedom - it has to execute the type initializer at some point before the first use of a static field or before an instance is constructed, but that's all. You can even observe static methods which don't touch static fields being executed without the type initializer executing.
In your case, both A and B have static constructors, and the order of access to the members is B first, then A, hence your output. Without those static constructors, you'd still be guaranteed to get "1 1" as the last line, and you'd still get both "Init A" and "Init B", but the ordering of them wouldn't be guaranteed.
This is just the way the language and runtime are specified - and usually it has no impact, as usually type initializers should just be setting up the type, with no other side effects. Type initializers should do as little as possible, ideally - if they fail for some reason, the type will never be usable; type initializers aren't retried.
For more details, see my beforefieldinit article and .NET 4.0 type initializer changes blog post.
My app uses several "handles" (all IntPtr's) of varying "type".
I want to help ensure that the correct handle type are passed to my various methods... if I used IntPtr for them all then there's no hint that the method takes handle type A or handle type B.
If L were in C++ land I could use typedefs:
typedef uint32 HdlA;
typedef uint32 HdlB;
and now I have two types, HdlA and HdlB, both of which are generic U32's under the hood.
In C++ I could also use a macro to declare the structs.
Additionally, for marshaling reasons, I need these to be value types... can't use a class (naturally, if I could use class that would solve everything).
All handles have essentially identical definitions:
public struct HdlA
{
private IntPtr _h;
public bool IsValid get { return (_h != IntPtr.Zero);} }
//public HdlA() { _h = IntPtr.Zero; } // C# disallows arg-less ctor on struct
public HdlA(IntPtr h) { _h = h; }
public void Invalidate() { _h = IntPtr.Zero; }
public static implicit operator IntPtr(HdlA hdl) { return hdl._h; }
}
public struct HdlB
{
private IntPtr _h;
public bool IsValid get { return (_h != IntPtr.Zero);} }
//public HdlB() { _h = IntPtr.Zero; } // C# disallows arg-less ctor on struct
public HdlB(IntPtr h) { _h = h; }
public void Invalidate() { _h = IntPtr.Zero; }
public static implicit operator IntPtr(HdlB hdl) { return hdl._h; }
}
... etc ...
I certainly can do this longhand - I can declare 5 or 6 identical blocks of code where only the struct names vary - but that's not very elegant.
I've considered using an Interface, but that disallows member fields, so no luck there.
What I'd love is to have a base struct then have HdlA, HdlB, etc simply derive off the base. But C# disallows base types in structs.
This seems like something that should have an easy and elegant solution, but it's escaping me :(
Any ideas?
One solution is to use only one struct with all common fields and add a field(int or Enum) that shows the type of the struct you want to use. Of course if you were able to use classes you would have used Inheritance but in this scenario adding a HandleType field may solve the problem.
You can then check that field in each method to see the right struct has been passed or not.
You don't provide a great deal of context in your question, so I'm stabbing wildly in the dark here.
It might be possible to use classes in your situation, after all. Declare the abstract base class, derive HndlA and HndlB from it, and provide a ToHandle() method on the base class that converts the class to a struct. The value from ToHandle() would be the object you marshal.
Again, just stabbing wildly in the dark.
In C++ I could also use a macro to declare the structs.
In C# you can use a T4 template.
Or strictly, it's not C# itself, though it can use C# as both the script language, and the output, and it can be part of the build in pretty much any build tool for C# (VisualStudio, MonoDevelop, SharpDevelop, Nant) other than just calling the compiler itself.
Create a file with a .tt or .t4 extension like:
<## template language="C#" #>
<## output extension=".generated.cs" #>
namespace SomeNamespace
{
<#
foreach(string name in new string[]{"HdlA", "HdlB", /*… and so on… */})
{#>
public struct <#=name#>
{
private IntPtr _h;
public bool IsValid
{
get { return (_h != IntPtr.Zero); }
}
public <#=name#>(IntPtr h)
{
_h = h;
}
public void Invalidate()
{
_h = IntPtr.Zero;
}
public static implicit operator IntPtr(<#=name#> hdl)
{
return hdl._h;
}
}
<#}#>
}
It works pretty much as ASP.NET does, but produces a local file. Here we use it to produce a .cs file that will then be part of the compilation, rebuilding the .cs file first if necessary. Alas, while it's a generated file, it causes problems if you don't include it in your source control (must start a question on that irritation).
Here is a real example of mine that's a bit more realistic. Here rather than wanting similar classes with different names, I wanted different methods with different types, but it's the same basic principle.
By the way,
// C# disallows arg-less ctor on struct
Depending on how you look at it, you could also say that it insists that you must have a predefined arg-less zero-filling constructor, that you can't get rid of or replace (there's [usually] no such method, but we do use new blah() in the calling C#). While it's possible in .NET to do otherwise, the differences in the cases where it is called or where zero-filling happens cause enough confusion that insisting that the constructor match zero-filling does save some problems.
My question is a bit similar to this one: How to convert an action to a defined delegate of the same signature?
Why there is no implicit convertion between delegates with same signature. For example, code:
class Program
{
private delegate void Foo1(int x);
private delegate void Foo2(int x);
static void Main(string[] args)
{
Foo1 foo1 = Console.WriteLine;
Foo2 foo2 = Console.WriteLine;
Call(foo1);
Call2(foo2);
}
static void Call(Action<int> action)
{
action(10);
}
static void Call2(Foo1 action)
{
action(10);
}
}
it does not compile because there isn't implicit convertion from Action<int> to Foo1.
But normaly it's the same thing. So it mean this names are aliases, not actualy names. So i think it was great idea to think about it like aliases. So in this case we have 3 aliases of a delegate, that get one int value and returns nothing. And this delegates are fully interchangeable one by another. But we don't have it. So question is: why? By signatures it's the same thing, and there isn't any implementation, so delegates with same signature are one and same with many aliases...
Is it C# defect or there are reasons for it? As to me, i don't see any.
There's no implicit conversion between those two delegates for the same reason that there's no implicit conversion between these two types:
public sealed class Foo1
{
public string Value { get; set; }
}
public sealed class Foo2
{
public string Value { get; set; }
}
Just because two classes have the same fields doesn't mean that you should be able to treat one as if it were another. The same logic applies to delegates (which are also types, mind you).
There is semantic meaning applied to the creation of that type. If someone created a Foo1 they want it to be a Foo1, not a Foo2. If they're going out of their way to use a Foo1 where a Foo2 is expected, it's a big red flag that even though the types appear similar, there is a semantic difference between these two types. If the programmer knows something that the compiler doesn't, they can use an explicit conversion of some sort to indicate that they know what they're doing.
(The previous paragraph was intentionally written to apply equally to your delegates, and the classes I provided above.)
I have some properties used to access fields from a parent class like so:
Class A:
private int _number = 42;
public virtual int Number { get { return _number; } }
Class B : A:
public override int Number { get { return base.Number + 1; } }
My question is, if I access B.Number, will it still resolve to a direct access to A._number (+ 1)?
This is assuming an optimized Release build, of course.
More importantly, are access modifiers abstract (as in they only matter when compiling and do not have an impact on code when running), or will they actually restrict access at runtime (other than when using Reflection, of course)?
Well they are abstract in the sense that they don't affect runtime performance but the information still needs to be stored in the compiled IL for cases where e.g security manager is enabled.
And no, the call to the getter function here wasn't inlined in x64 nor x86.
public static void Main(string[] args) {
B b = new B();
int a = b.Number;
}
You can use these instructions to disassemble the jitted code and see for yourself too.