.NET: Determine whether object is partially or fully constructed - c#

Is there any way to query the .NET runtime to determine whether an object has finished its construction, or if the construction is still on-going and/or was aborted with an exception?
Basically, something equivalent to:
class Foo {
public string ConstructionState { get; private set; }
public Foo() {
try {
ConstructionState = "ongoing";
// ... do actual constructor stuff here ...
ConstructionState = "completed";
}
catch (Exception) {
ConstructionState = "aborted";
throw;
}
}
}
... except also taking into account field initializers, base class constructors etc., and without needing to modify the constructor.

A well-behaved object should never expose itself until it's fully constructed. If a partially constructed object is leaked, you're already violating that contract.
The runtime doesn't care, of course. There's nothing special about a partially-constructed object as far as the runtime is concerned - it's still subject to the same memory constraints, finalization and garbage collection as a fully constructed object.
If you own the object, the solution is simple - don't leak the object during construction. The usual way to do some global change during object initialisation is to use a static method (or a factory) instead of a constructor. If you don't own the object, you're pretty much out of luck.
The runtime specification doesn't explicitly say there's no way to check if an object is partially constructed, but it doesn't say there is either (as far as I can tell) - so even if you found some way, it wouldn't be safe to rely on it. Inspecting by hand shows that .NET object headers have no such information, and a disassembly of the constructor shows there's no non-user code after a constructor finishes that could update such a state.
The runtime does store a few flags in "weird" places. The mark & sweep garbage collector in desktop MS.NET stores its marks in an "unused" bit of the pointer to the virtual method table, for example. But as far as the runtime is concerned, the object is "done" even before any of its constructors run - all of that is handled during the allocation in newobj, before the constructor (a special instance method) runs. The object header (which also contains the object size) and virtual method table (so the object is of the most derived type even before the constructors run) are already set here, and all the memory directly used by that instance is already allocated (and pre-zeroed - so you don't get pointers to random bits of memory). This means that memory safety isn't impacted by partially-constructed objects as far as the runtime is concerned.
The main difference between a constructor and another instance method is that the constructor must only ever be called once on any instance. On the CIL level, this is enforced simply by the fact that you can't invoke the constructor directly - you only ever use newobj, which pushes the constructed object on the stack. Just like with other instance methods, it doesn't track if a particular method finishes or not - after all, it's perfectly legal to have a method that never finishes, and you can actually do the same thing with a (non-static) constructor.
If you want a proof that the runtime doesn't care, I present to you... the object can be collected by the GC before the constructor even finishes:
class Test
{
public static WeakReference<Test> someInstance;
public static void AliveTest()
{
Test t;
if (someInstance == null) Console.WriteLine("Null");
else Console.WriteLine(someInstance.TryGetTarget(out t));
}
public Test()
{
someInstance = new WeakReference<Test>(this);
AliveTest();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
AliveTest();
}
}
class Program
{
static void Main(string[] args)
{
Test t = new Test();
Test.AliveTest();
Console.ReadLine();
}
}
This test program writes out True, False, False (make sure to run it in Release mode and without the debugger - .NET prevents many things like this to make debugging easier). The object has been collected before its constructor even finished, which means that there's no special treatment for constructors in this regard. Another reason not to use the "constructor updates something static" pattern, and especially not the "finalizer updates it back". If you add a finalizer to this sample code, it will run before the constructor finishes. Ouch.
Even your solution would be insufficient in the general case. To cite CLI specification:
It is explicitly not a requirement that a conforming implementation of the CLI guarantee that all state updates performed within a constructor be uniformly visible before the constructor completes.
There's no guarantee another thread would have correct information about the construction state.
For bonus points, it also doesn't help if the object isn't sealed. A derived classes constructor would run after the base class constructor and in C# there's no way to rewrite this to encompass all the constructors that normally run in a sequence. The best you could do is maintain a separate "constructed state" for each constructor, which is confusing at best (and breaks a few OOP principles - it would require all consumers of the object to know of all possible types the object could have).

Related

Obtaining a reference to an instance whose constructor had thrown an exception

Consider the following issue
When designing a framework, an interface exposing some event is presented
interface I
{
event MyEventHandler MyEvent
}
This interface will eventually be implemented by many different 3rd party vendors, and may be consumed by various clients.
Since each vendor may new up the event args with invalid data, the only control I have as a framework author is at the event args level, so I thought of the following pattern:
class MyEventArgs
{
public int? MyProperty{get;}
MyEventArgs(int arg)
{
if(arg.IsInvalidArgument())//Let's pretend that there's such an extension method
throw new ArgumentException(...)
MyProperty = arg;
}
This ensures that a client can not use invalid values provided by some rogue piece of code, since the constructor throws an exception, hence the integer will have no value assigned, making it a null reference.
However, this also creates overhead in client code, since now the client has to check the HasValue and then access Value, making the EventArgument less user friendly.. This becomes even more cumbersome when the amount of parameters per event argument grow.
I could technically remove the question mark, which would rid the client of the Nullable nonsense, since in my opinion there is no way on god's green earth to obtain a reference to such an instance, but the problem is that this scenario, although easy to test, may have edge cases which I never thought of, hence my question.
Is there any possible way to obtain a reference to an instance whose constructor had thrown an exception and pass it to the event listeners?
When a constructor throws an exception there is no way to obtain a reference to that object (except if the object cooperates by handing out this before throwing; not likely, bad design).
For that reason your invalidly valued object is unreachable. It's state is indeed invalid (default initialized) but nobody can see it. It's like a virtual machine that is corrupted on the inside and tries to launch missiles but you have disabled the virtual NIC.
This pattern is used all over the place. You have used it many times without realizing. For example, if you say new FileStream(null) how would you obtain a reference to that invalid stream? You can't.
Just do the normal thing. It's good that you thought this through, though.
Is there any possible way to obtain a reference to an instance whose constructor had thrown an exception and pass it to the event listeners?
No. But here's an example where it's possible:
class C {
public static C Instance;
public C() {
Instance = this; //publish/leak
throw ...;
}
}
Just don't do that. This is unnatural code anyway. The constructor of an object normally should not do much, it should bring the object into a valid state and not cause side-effects. Side-effects are the only way to publish a reference to this.
There's one more catch: A finalizer will be invoked on that object if one is present. Finalizers are rare because because most of the time unmanaged resources should be held by handle classes. For that reason this issue rarely comes into effect. But a finalizer can see the private state of its object. Make sure that it can deal with that. FileStreams finalizer will probably check for aborted initialization and do nothing.
the client has to check the HasValue and then access Value
Well it's not necessary to make the property a Nullable<int>, as you can only set it from the constructor (assuming an omitted private set), where it is non-nullable.
Is there any possible way to obtain a reference to an instance whose constructor had thrown an exception
No, when a constructor throws an exception, you don't get an instance back.
To answer your question. No. you can't have a null result if an error is encountered in a constructor
However I think the best possible way around this is to add a static constructing function to the MyEventArgs class
public static int DEFAULT_ARG = 1;//you can set this to whatever you want
public static Create(int arg)
{
if(checkArg(arg))
{
return new MyEventArgs(arg);
}
return new MyEventArgs(MyEventArgs.DEFAULT_ARG);
}
Then instead of using the constructor directory using var event = new MyEventArgs(arg); you use var event = MyEventArgs.Create(arg);
It's a bit of a stress using this method on multiple eventargs but hey :) you could always derive all of them from the same generic abstract class
Hope this helps :)

Could a class instance that is not being assigned to a variable get garbage-collected too early?

(I don't even know whether my question makes sense at all; it is just something that I do not understand and is spinning in my head for some time)
Consider having the following class:
public class MyClass
{
private int _myVar;
public void DoSomething()
{
// ...Do something...
_myVar = 1;
System.Console.WriteLine("Inside");
}
}
And using this class like this:
public class Test
{
public static void Main()
{
// ...Some code...
System.Console.WriteLine("Before");
// No assignment to a variable.
new MyClass().DoSomething();
// ...Some other code...
System.Console.WriteLine("After");
}
}
(Ideone)
Above, I'm creating an instance of a class without assigning it to a variable.
I fear that the garbage collector could delete my instance too early.
My naive understanding of garbage collection is:
"Delete an object as soon as no references point to it."
Since I create my instance without assigning it to a variable, this condition would be true. Obviously the code runs correct, so my asumption seems to be false.
Can someone give me the information I am missing?
To summarize, my question is:
(Why/why not) is it safe to instantiate a class without asigning it to a variable or returning it?
I.e. is
new MyClass().DoSomething();
and
var c = new MyClass();
c.DoSomething();
the same from a garbage collection point-of-view?
It's somewhat safe. Or rather, it's as safe as if you had a variable which isn't used after the method call anyway.
An object is eligible for garbage collection (which isn't the same as saying it will be garbage collected immediately) when the GC can prove that nothing is going to use any of its data any more.
This can occur even while an instance method is executing if the method isn't going to use any fields from the current execution point onwards. This can be quite surprising, but isn't normally an issue unless you have a finalizer, which is vanishingly rare these days.
When you're using the debugger, the garbage collector is much more conservative about what it will collect, by the way.
Here's a demo of this "early collection" - well, early finalization in this case, as that's easier to demonstrate, but I think it proves the point clearly enough:
using System;
using System.Threading;
class EarlyFinalizationDemo
{
int x = Environment.TickCount;
~EarlyFinalizationDemo()
{
Test.Log("Finalizer called");
}
public void SomeMethod()
{
Test.Log("Entered SomeMethod");
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(1000);
Test.Log("Collected once");
Test.Log("Value of x: " + x);
GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(1000);
Test.Log("Exiting SomeMethod");
}
}
class Test
{
static void Main()
{
var demo = new EarlyFinalizationDemo();
demo.SomeMethod();
Test.Log("SomeMethod finished");
Thread.Sleep(1000);
Test.Log("Main finished");
}
public static void Log(string message)
{
// Ensure all log entries are spaced out
lock (typeof(Test))
{
Console.WriteLine("{0:HH:mm:ss.FFF}: {1}",
DateTime.Now, message);
Thread.Sleep(50);
}
}
}
Output:
10:09:24.457: Entered SomeMethod
10:09:25.511: Collected once
10:09:25.562: Value of x: 73479281
10:09:25.616: Finalizer called
10:09:26.666: Exiting SomeMethod
10:09:26.717: SomeMethod finished
10:09:27.769: Main finished
Note how the object is finalized after the value of x has been printed (as we need the object in order to retrieve x) but before SomeMethod completes.
The other answers are all good but I want to emphasize a few points here.
The question essentially boils down to: when is the garbage collector allowed to deduce that a given object is dead? and the answer is the garbage collector has broad latitude to use any technique it chooses to determine when an object is dead, and this broad latitude can lead to some surprising results.
So let's start with:
My naive understanding of garbage collection is: "Delete an object as soon as no references point to it."
This understanding is wrong wrong wrong. Suppose we have
class C { C c; public C() { this.c = this; } }
Now every instance of C has a reference to it stored inside itself. If objects were only reclaimed when the reference count to them was zero then circularly referenced objects would never be cleaned up.
A correct understanding is:
Certain references are "known roots". When a collection happens the known roots are traced. That is, all known roots are alive, and everything that something alive refers to is also alive, transitively. Everything else is dead, and eligable for reclamation.
Dead objects that require finalization are not collected. Rather, they are kept alive on the finalization queue, which is a known root, until their finalizers run, after which they are marked as no longer requiring finalization. A future collection will identify them as dead a second time and they will be reclaimed.
Lots of things are known roots. Static fields, for example, are all known roots. Local variables might be known roots, but as we'll see below, they can be optimized away in surprising ways. Temporary values might be known roots.
I'm creating an instance of a class without assigning it to a variable.
Your question here is a good one but it is based on an incorrect assumption, namely that a local variable is always a known root. Assigning a reference to a local variable does not necessarily keep an object alive. The garbage collector is allowed to optimize away local variables at its whim.
Let's give an example:
void M()
{
var resource = OpenAFile();
int handle = resource.GetHandle();
UnmanagedCode.MessWithFile(handle);
}
Suppose resource is an instance of a class that has a finalizer, and the finalizer closes the file. Can the finalizer run before MessWithFile? Yes! The fact that resource is a local variable with a lifetime of the entire body of M is irrelevant. The runtime can realize that this code could be optimized into:
void M()
{
int handle;
{
var resource = OpenAFile();
handle = resource.GetHandle();
}
UnmanagedCode.MessWithFile(handle);
}
and now resource is dead by the time MessWithFile is called. It is unlikely but legal for the finalizer to run between GetHandle and MessWithFile, and now we're messing with a file that has been closed.
The correct solution here is to use GC.KeepAlive on the resource after the call to MessWithFile.
To return to your question, your concern is basically "is the temporary location of a reference a known root?" and the answer is usually yes, with the caveat that again, if the runtime can determine that a reference is never dereferenced then it is allowed to tell the GC that the referenced object might be dead.
Put another way: you asked if
new MyClass().DoSomething();
and
var c = new MyClass();
c.DoSomething();
are the same from the point of view of the GC. Yes. In both cases the GC is allowed to kill the object the moment that it determines it can do so safely, regardless of the lifetime of local variable c.
The shorter answer to your question is: trust the garbage collector. It has been carefully written to do the right thing. The only times you need to worry about the GC doing the wrong thing are scenarios like the one I laid out, where timing of finalizers is important for the correctness of unmanaged code calls.
Of course, GC is transparent to you and no early collection can ever happen. So I guess you want to know the implementation details:
An instance method is implemented like a static method with an additional this parameter. In your case the this value lives in registers and is passed like that into DoSomething. The GC is aware what registers contain live references and will treat them as roots.
As long as DoSomething might still use the this value it stays live. If DoSomething never uses instance state then indeed the instance can be collected while a method call is still running on it. This is unobservable, therefore safe.
As long as you're talking about a single threaded environment, you're safe. Fun things only start to happen if you're starting a new thread inside the DoSomething method, and even more fun happens if your class has a finalizer. The key thing to understand here is that a lot of the contracts between you and the runtime / optimizer / etc. are valid only in a single thread. This is one of the things that has disastrous results when you start programming on multiple threads in a language that isn't primaririly multi-threading oriented (yes, C# is one of those languages).
In your case, you're even using the this instance, which makes unexpected collection even less likely while still inside that method; in any case, the contract is that on a single thread, you can't observe the difference between the optimized and unoptimized code (apart from memory usage, speed, etc., but those are the "free lunch").

Garbage Collector, call & callvirt and Debug/Release code mode execution differences

I have a class:
public class SomeClass {
public int I;
public SomeClass(int input) {
I = input;
Console.WriteLine("I = {0}", I);
}
~SomeClass() {
Console.WriteLine("deleted");
}
public void Foo() {
Thread.Sleep(1000);
Console.WriteLine("Foo");
}
}
and this program:
class Program {
static void Main(string[] args) {
new Thread(() => {
Thread.Sleep(100);
GC.Collect();
}) { IsBackground = true }.Start();
new SomeClass(10).Foo();
// The same as upper code
// var t = new SomeClass(10);
// t.Foo();
}
}
When i run this code in Debug mode, i have next result:
I = 10
Foo
deleted
but, when i change mode to Release, result changes to:
I = 10
deleted
Foo
As i understand, there is difference with call and callvirt: when optimization starts in Release mode, compiler look at Foo method and can't find any reference to SomeClass in this method, and that's why this method calls as static method by address, and garbage collector could collect this object.
Otherwise, if i change Foo method (for example, add Console.WriteLine(I) into this method), compiler won't decide to call this method as call and it should be called by pointer to instance with callvirt and garbage collector won't collect this object.
Can you please explain more clearly, what's going on here (why GC could collect object and if it's so, how does method calls).
I doubt that it's really anything to do with call and callvirt.
I strongly suspect it's simply because you're not using any fields within SomeClass.Foo. The garbage collector is free to collect an object when it is certain that none of the data will be referenced again - so no code is going to look at any references to the object, or any fields within the object.
Basically, if you write a finalizer and you need to ensure that the object isn't finalized while methods within that object are running, you need to be very careful. You can use GC.KeepAlive(this) at the end of methods, as one approach, but it's a bit ugly. I would personally try very hard to avoid needing a finalizer at all, if you can. I can't remember the last time I wrote one. (See Joe Duffy's blog for more.)
When there's a debugger attached, the GC is much less aggressive about what it can collect - after all, if you can break into the debugger at any point and inspect the fields of any object that is the target of a running instance method, that removes the possibility of garbage collecting those objects.
When you're debugging, the whole system1 extends the lifetime of objects beyond their natural lifetime.
So, when a thread is executing this method:
public void Foo() {
Thread.Sleep(1000);
Console.WriteLine("Foo");
}
This method makes no use of this. So when not debugging, after this method has started running, it doesn't require the object to exist any longer.
However, when debugging, you might have set a breakpoint on that Console.WrtieLine method, and from there decide to inspect this. So the system conspires to keep this alive (as well as any local variables which are no longer used within the body of a method).
1This old presentation shows how the JIT and GC actually work together to work out which references are live (see slide 30 onwards). It is my understanding that the JIT does more work to help out with debugging - by not reusing local variable slots which it could (so values are still visible) and by informing the GC that all variables are alive throughout the method, rather than the more piecemeal analysis it can provide.

Is it really a bug in JIT optimization or am I missing something?

[TestFixture]
public class Tests
{
private class Relay
{
public Action Do { get; set; }
}
[Test]
public void OptimizerStrangeness()
{
var relay = new Relay();
var indicator = 0;
relay.Do = () => indicator++;
var weak = new WeakReference(relay);
GC.Collect();
var relayNew = weak.Target as Relay;
if (relayNew == null) Assert.Fail();
relayNew.Do();
Assert.AreEqual(1, indicator);
}
}
This code fails only in Release mode at Assert.Fail() line despite the fact relay variable is still in scope and thus we still have strong reference to the instance, so WeakReference must not be dead yet.
UPD: To clarify a bit: I realize that it can be 'optimized away'. But depending on this optimization indicator variable would have 0 or 1 value, i.e. we have actual visible change of behavior.
UPD2: From C# language specification, section 3.9
If the object, or any part of it, cannot be accessed by any possible continuation of execution, other than the running of
destructors, the object is considered no longer in use, and it becomes
eligible for destruction. The C# compiler and the garbage collector
may choose to analyze code to determine which references to an object
may be used in the future. For instance, if a local variable that is
in scope is the only existing reference to an object, but that local
variable is never referred to in any possible continuation of
execution from the current execution point in the procedure, the
garbage collector may (but is not required to) treat the object as no
longer in use.
Technically speaking, this object can and will be accessed by continuation of execution and thus can't be treated as 'no longer in use' (actually C# spec says nothing about weak references because it is aspect of CLR and not the compiler - compiler output is fine). Will try to search for memory management info about CLR/JIT.
UPD3: Here is some info on CLR's memory management - section 'Releasing memory':
...Every application has a set of roots. Each root either refers to an
object on the managed heap or is set to null. An application's roots
include global and static object pointers, local variables and
reference object parameters on a thread's stack, and CPU registers.
The garbage collector has access to the list of active roots that the
just-in-time (JIT) compiler and the runtime maintain. Using this list,
it examines an application's roots, and in the process creates a graph
that contains all the objects that are reachable from the roots.
Variable in question is definitely local variable, hence it is reachable. Thus said, this mention is very quick/vague, so I would be really glad to see more concrete info.
UPD4: From sources of .NET Framework:
// This method DOES NOT DO ANYTHING in and of itself. It's used to
// prevent a finalizable object from losing any outstanding references
// a touch too early. The JIT is very aggressive about keeping an
// object's lifetime to as small a window as possible, to the point
// where a 'this' pointer isn't considered live in an instance method
// unless you read a value from the instance. So for finalizable
// objects that store a handle or pointer and provide a finalizer that
// cleans them up, this can cause subtle ----s with the finalizer
// thread. This isn't just about handles - it can happen with just
// about any finalizable resource.
//
// Users should insert a call to this method near the end of a
// method where they must keep an object alive for the duration of that
// method, up until this method is called. Here is an example:
//
// "...all you really need is one object with a Finalize method, and a
// second object with a Close/Dispose/Done method. Such as the following
// contrived example:
//
// class Foo {
// Stream stream = ...;
// protected void Finalize() { stream.Close(); }
// void Problem() { stream.MethodThatSpansGCs(); }
// static void Main() { new Foo().Problem(); }
// }
//
//
// In this code, Foo will be finalized in the middle of
// stream.MethodThatSpansGCs, thus closing a stream still in use."
//
// If we insert a call to GC.KeepAlive(this) at the end of Problem(), then
// Foo doesn't get finalized and the stream says open.
[System.Security.SecuritySafeCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static extern void KeepAlive(Object obj);
See here for my investigation in more details, if you're interested.
Even if a variable is in scope, the runtime is free to collect it if it's no longer accessed in any future code path. This is why when debugging an assembly with JIT optimizations in place can give you a message about a variable's value being optimized away even though it's currently in scope.
See item 2 on 3.9 Automatic Memory Management.
To be specific,
For instance, if a local variable that is in scope is the only existing reference to an object, but that local variable is never referred to in any possible continuation of execution from the current execution point in the procedure, the garbage collector may (but is not required to) treat the object as no longer in use.
This is the crucial point; the object is considered to be inaccessible because all strong references to the object (there's only one) are unreachable. Remember that the C# spec will contain information about the language as well as information about how the compiled code should execute. Also remember that reachability is not defined by scope. As the spec states, if the compiler and runtime can determine that a variable is not present in any future code path (meaning they are never referenced at all or only referenced in paths that are determined to be unreachable, like if(false)), then the variable is considered unreachable and does not count as a strong reference.
While that particular portion of the specification does not state WeakReference explicitly, it doesn't need to. You have only one local variable that ever points to that value as far as the compiler is concerned.
WeakReference is just another class that takes an object as an argument; from the perspective of the compiler; it has no reason to believe (or make an assumption one way or the other) about whether or not that class holds on to the reference that it's passed. Consider if I had a class like this that was used instead:
public class MyClass
{
public MyClass(object foo)
{
Console.WriteLine(foo);
}
}
And in my code I did this:
var relay = new Relay();
...
var myClass = new MyClass(relay);
I haven't introduced any new strong references to the value I assigned to relay, as MyClass doesn't hold on to that reference. The fact that WeakReference is a "special" class that is designed to give you a reference to an object that doesn't count as a strong reference is irrelevant as far as the compiler is concerned.
Reachability is not defined by scope; it's defined by whether or not the variable (not value) in question lies in any possible future code path. As relay is not present in any form later in the function, the variable (and thus its reference to the object) is considered unreachable and eligible for collection. This is the reason the DisableOptimizations flag exists at the assembly level so that the runtime knows (among other things) to wait until the variable falls out of scope before it's eligible for collection so that it is accessible to the debugger.

C# static garbage collector?

I have a simple class which has a static constructor and a instance constructor. Now when i initialized the class , both static and instance constructor are called. Only static is referred once in a application domain . Can i again call the same class initialization and static constructor initialize again? I have tried but it didn't happen? Is there any way we can call static constructor again in main() method after using garbage collection on the class.
Here is the code:
public class Employee
{
public Employee()
{
Console.WriteLine("Instance constructor called");
}
static Employee()
{
Console.WriteLine("Static constructor called");
}
~Employee()
{
//Dispose();
}
}
Now in main method call:
static void Main(string[] args)
{
Employee emp = new Employee();
Employee emp = new Employee();
}
Output:
Static constructor called
Instance constructor called
Instance constructor called
Now the static didn't called again. Because it is called once in application domain. But is their any way we could call it again without unloading application domain. Can we use GC class over here?
Thanks.
Pal
Unless you prod it with reflection, the static constructor (or more generally, the type initializer) is only executed once per concrete class, per AppDomain.
Note that for generics, using different type arguments you'll get different concrete classes:
public class Foo<T>
{
Foo()
{
Console.WriteLine("T={0}", typeof(T));
}
public static void DummyMethod() {}
}
...
Foo<int>.DummyMethod(); // Executes static constructor first
Foo<string>.DummyMethod(); // Executes static constructor first
Foo<string>.DummyMethod(); // Type is already initialized; no more output
Not possible. The CLR keeps an internal status bit that tracks whether the type initializer was started. It cannot run again. That status bit is indeed stored in the loader heap as part of the AppDomain state. The workaround is simple, just add a static method to the class.
The point of a constructor is to put things into a desired initial valid state.
An instance constructor puts an instance into an initial valid state.
An instance constructor that takes arguments puts an instance into a initial valid state that reflects its arguments.
A static constructor puts the type into an initial valid state. E.g. initialising static members used by the class' static methods or shared by all instances.
Ideally all methods will leave the object and the type in a valid state, but constructors differ in being responsible for getting it into one in the first place.
Any attempt to call a constructor twice is therefore a mistake, since "put it into an initial valid state again" isn't something you can logically do twice ("initial" and "again" don't work well in the same clause). We are helped by the compiler (in it refusing to compile) and the language (in there being no way to express this) from doing such a thing.
And, being a logical impossibility it isn't something you can actually want to do (well, I can want to draw a triangle with more than 3 sides, but only to say that I did). This suggests that you are using your constructor to do something other than setting up an initial valid state.
Doing anything other than establishing such a valid state in a constructor is (as is failing to do so) at best an optimisation, quite often a serious design flaw and quite possibly (worse of all because it goes unfixed longer) an attempted optimisation that is really a serious design flaw.
One sign that your attempt at an optimisation is really a design flaw is a desire to call a static constructor more than once, or to call an instance constructor more than once on the same object.
Identify the desired repeatable behaviour, move it into a separate method, and have it called as needed from both the constructor and elsewhere. Then double check your design's logic, as this is quite a serious mistake to find in a class design and suggests you've got deeper problems.

Categories