4

Is it possible to create an object that can register whether the current thread leaves the method where it was created, or to check whether this has happened when a method on the instance gets called?

ScopeValid obj;

void Method1()
{
    obj = new ScopeValid();
    obj.Something();
}

void Method2()
{
    Method1();
    obj.Something(); //Exception
}

Can this technique be accomplished? I would like to develop a mechanism similar to TypedReference and ArgIterator, which can't "escape" the current method. These types are handled specially by the compiler, so I can't mimic this behavior exactly, but I hope it is possible to create at least a similar rule with the same results - disallow accessing the object if it has escaped the method where it was created.

Note that I can't use StackFrame and compare methods, because the object might escape and return to the same method.

IS4
  • 11,945
  • 2
  • 47
  • 86
  • 4
    What's your use case here? In your example it almost seems the intent would be better expressed with `obj` being local to `Method1()` – jdphenix Apr 26 '15 at 20:31
  • The code that uses `ScopeValid` is user-created. Even if I say one can't do this, some nasty programmer might break it, so I wonder if it can be enforced. – IS4 Apr 26 '15 at 20:32
  • 1
    Okay, but what is the use-case of making a method scoped member that other methods could reference and attempt to use? – jdphenix Apr 26 '15 at 20:41
  • @jdphenix I don't understand. `ArgIterator` can't be used outside the method, because it accesses the arguments passed to the method, which only exist inside it. `ScopeValid` would do something similar, so a similar enforcement would come in handy. – IS4 Apr 26 '15 at 20:47
  • *Why do you want to implement this?* - That's about as clear as I can be I think. – jdphenix Apr 26 '15 at 20:50
  • @jdphenix I thought the question answers it. Partly because of curiosity and partly because of limiting nasty programmers to prevent them from doing something bad. – IS4 Apr 26 '15 at 20:52
  • But why not just declare the variable on the method scope? Why would you want a class scope variable to be valid only in a single method? – Zohar Peled Apr 26 '15 at 21:17
  • @Zohar I am not talking about a variable, but about an object. And as I also said previously, the example code can be written by someone else who isn't aware of the fact that the object is invalid outside the method, or just wants an undefined behavior caused by manipulating invalid memory to occur. The object may work with pointers valid only in the current method scope, and there isn't arbiraty method to check whether a pointer is valid. – IS4 Apr 26 '15 at 21:23

2 Answers2

7

Changing method behavior based upon the source of the call is a bad design choice.

Some example problems to consider with such a method include:

  • Testability - how would you test such a method?
  • Refactoring the calling code - What if the user of your code just does an end run around your error message that says you can't do that in a different method than it was created? "Okay, fine! I'll just do my bad thing in the same method, says the programmer."

If the user of your code breaks it, and it's their fault, let it break. Better to just document your code with something like:

IInvalidatable - Types which implement this member should be invalidated with Invalidate() when you are done working with this.

Ignoring the obvious point that this almost seems like is re-inventing IDisposible and using { } blocks (which have language support), if the user of your code doesn't use it right, it's not really your concern.


This is likely technically possible with AOP (I'm thinking PostSharp here), but it still depends on the user using your code correctly - they would have to have it in the build process, and failing to function if they aren't using a tool just because you're trying to make it easy on them is evil.

Another point - If you are just attempting to create an object which cannot be used outside of one method, and any attempted operation outside of the method would fail, just declare it a local inside the method.

Related: How to find out which assembly handled the request

Community
  • 1
  • 1
jdphenix
  • 15,022
  • 3
  • 41
  • 74
0

Years laters, it seems this feature was finally added to C# 7.2: ref struct.

Another related language feature is the ability to declare a value type that must be stack allocated. In other words, these types can never be created on the heap as a member of another class. The primary motivation for this feature was Span and related structures. Span may contain a managed pointer as one of its members, the other being the length of the span. It's actually implemented a bit differently because C# doesn't support pointers to managed memory outside of an unsafe context. Any write that changes the pointer and the length is not atomic. That means a Span would be subject to out of range errors or other type safety violations were it not constrained to a single stack frame. In addition, putting a managed pointer on the GC heap typically crashes at JIT time.

This prevents the code from moving the value to the heap, which partly solves my original problem. I am not sure how returning a ref struct is constrained, though.

IS4
  • 11,945
  • 2
  • 47
  • 86
  • Observation: If you want to "capture" a `ref struct`, you can still do so by trapping it in a paused thread. I have used a similar technique to pin a reference indefinitely without using *GCHandle*, by emitting `pinned` in CIL and then pausing the thread. – IS4 Nov 29 '17 at 09:54