Require that all calls come from code in a specific class

Tygur

Regular
Joined
Oct 2, 2003
Messages
68
I have a function that takes a Type object as one of its arguments, and I'd like to make sure that it only gets called from code within the class indicated by the given Type. What's the best, most performant way of doing this?

Thanks in advance!
 
I believe you'll want to use Reflection. I don't thikn there is a way that you can prevent your function from being called, but in your function you might be able to detect (via Reflection) if the calling object is of the correct type and then either return or continue working.
 
Well, it has already occurred to me to use the StackTrace class to check the call stack, but the problem is it's possible for methods to get optimized out, preventing them from showing up in the stack trace, and my code would never know. I was figuring there ought to be something in System.Security or elsewhere that'd account for that somehow and give me what I want. I suppose it'd also help if it turns out there's a way of marking a method so it doesn't get optimized out in the first place.

You can see what I'm talking about by comparing the output of this program when compiled for Debug or Release:
Code:
using System;
using System.Diagnostics;

public class Program {
    public static void Main(string[] args) {
        Stub();
        Console.ReadLine();
    }
    public static void Stub() {
        Check();
    }
    public static void Check() {
        StackTrace trace = new StackTrace(false);
        foreach (StackFrame frame in trace.GetFrames()) {
            Console.WriteLine(frame.GetMethod().Name);
        }
    }
}
When compiled for Release, Stub doesn't show up in the list. I'd like to work around or prevent that.
 
Cross type calls probably won't be optimized out

You've piqued my curiosity, and I'm interested as to why you want this behaviour. Perhaps there is another approach to achieve what you need - for example, marking the method as internal rather than public.

Well, it has already occurred to me to use the StackTrace class to check the call stack, but the problem is it's possible for methods to get optimized out, preventing them from showing up in the stack trace, and my code would never know.

Calls to methods within the same type might be optimized out, but I very much doubt calls to public methods in other types would be, which would need to happen for the type not to appear in the call stack. Have you tested this scenario by calling methods between types, rather than in the same type?
 
Re: Cross type calls probably won't be optimized out

You've piqued my curiosity, and I'm interested as to why you want this behaviour. Perhaps there is another approach to achieve what you need - for example, marking the method as internal rather than public.
In fact, the method has been internal up til now, and that has been fine, but now it needs to be made public because it can legitimately be called from outside the Assembly, but I still want it to only be called from within certain classes.

Calls to methods within the same type might be optimized out, but I very much doubt calls to public methods in other types would be, which would need to happen for the type not to appear in the call stack. Have you tested this scenario by calling methods between types, rather than in the same type?
Already tried it:
Code:
using System;
using System.Diagnostics;

public class Program {
    public static void Main(string[] args) {
        OtherClass.Stub();
        Console.ReadLine();
    }
    public static void Check() {
        StackTrace trace = new StackTrace(false);
        foreach (StackFrame frame in trace.GetFrames()) {
            Console.WriteLine(frame.GetMethod().Name);
        }
    }
}
public class OtherClass {
    public static void Stub() {
        Program.Check();
    }
}
Actually, I don't think it's the c# compiler doing it. I think it's being done by the jit compiler. Reflector still shows Stub() being called.
 
To MrPaul's original question: What is the end functionallity you are trying to get by requiring this method be called only by an instance of the type passed as a parameter?
 
The function I'm trying to protect is a convenience function that performs reflection on the Type in question and acts on what it finds. I actually have quite a few of them, and they all do something different. Their purpose is to make it easier to code the class represented by the Type that gets passed in. Instead of writing code directly into the class that does whatever, the class calls the convenience function, passing in its Type, and the function does the work. If other code bypasses the class and calls the convenience function directly, that violates some OOP principles, and makes the code harder to maintain. I'm trying to prevent that from ever happening.

It has occurred to me to make the class inherit from the class containing the convenience functions, and then making the functions protected. The functions could then use GetType() instead of acting on whatever type gets passed in. That's almost perfect, except it doesn't help any code in static methods inside my class. To support the static methods, the convenience functions would themselves have to be static, which means they can't rely on GetType() anymore. Without using GetType(), they're working on any Type that gets passed in, which still may or may not be that of the caller. Even if they're protected static, they can still be called by any other subclass and just be given the type of a different subclass.
 
Would it be possible to see an example of this functionality (or more detail about what these convenience functions do)?

It seems an awful lot of effort involved for something labelled as a convenience ;)
 
Would it be possible to see an example of this functionality (or more detail about what these convenience functions do)?

It seems an awful lot of effort involved for something labelled as a convenience ;)
Well, I was hoping not to go into it, because I didn't think it was needed to solve the problem at hand. What I made is a home-grown O/R mapper. The class (there are actually many of them tho) and its members have various attributes that tell my "convenience functions" how to access the database on its behalf. As I said, the problem is it's possible for other code to call the convenience functions directly, passing in the Type of the class, and bypassing the code in the class entirely. And because the class has static methods, I can't just toss the convenience functions into a base class.

I don't think it's that much effort, though. Reflection isn't terribly difficult. It'd be worse to rewrite such similar code across so many classes.

By the way, I've found a solution:
I had suspected that the optimization being performed by the jit compiler was called inlining, but I didn't state it because I hadn't bothered confirming it before starting this thread. A Google search revealed a way of preventing it. Simply add an atttribute to the method I don't want inlined (optimized out, as I'd been calling it before):
[MethodImpl(MethodImplOptions.NoInlining)]

Now I gotta see how all this affects performance...
 
If the class has such tight dependencies on the callers then (to me anyway) it suggests that it probably shouldn't be a public class or that the methods in question shouldn't be public.

However without seeing any code it is difficult to say what may be the cleanest solution...
 
If the class has such tight dependencies on the callers then (to me anyway) it suggests that it probably shouldn't be a public class or that the methods in question shouldn't be public.

However without seeing any code it is difficult to say what may be the cleanest solution...
I want to be able to put the "convenience functions" in one assembly, some of the classes that use them in another assembly, and maybe even more of them in a different assembly. The "convenience functions" themselves are really just tools that do what they're told, and I'd like to be able to use them from within multiple projects that themselves may or may not be very much related.
 
Back
Top