Determine Calling Object Type in C#

前端 未结 11 871
灰色年华
灰色年华 2021-02-05 14:37

Regardless of whether or not this is a good idea, is it possible to implement an interface where the executing function is aware of the calling object\'s type?

c         


        
相关标签:
11条回答
  • 2021-02-05 14:40

    You could use the System.Diagnostics.StackTrace class to create a stack trace. Then you could look for the StackFrame that is associated with the caller. The StackFrame has a Method property that you can use to get to the type of the caller.

    However, the above method is nothing that should be used in performance critical code.

    0 讨论(0)
  • 2021-02-05 14:41

    As an alternative approach, have you ever considered offering up a different class based on the type of the object that is asking for the class. Say the following

    public interface IC {
      int DoSomething();
    }
    
    public static CFactory { 
      public IC GetC(Type requestingType) { 
        if ( requestingType == typeof(BadType1) ) { 
          return new CForBadType1();
        } else if ( requestingType == typeof(OtherType) { 
          return new CForOtherType();
        }  
        ...
      }
    }
    

    This would be a much cleaner approach than have each method change it's behavior based on the calling object. It would cleanly separate out the concerns to the different implementations of IC. Additionally, they could all proxy back to the real C implementation.

    EDIT Examining the callstack

    As several other people pointed out you can examine the callstack to determine what object is immediately calling the function. However this is not a foolproof way to determine if one of the objects you want to special case is calling you. For instance I could do the following to call you from SomeBadObject but make it very difficult for you to determine that I did so.

    public class SomeBadObject {
      public void CallCIndirectly(C obj) { 
        var ret = Helper.CallDoSomething(c);
      }
    }
    
    public static class Helper {
      public int CallDoSomething(C obj) {
        return obj.DoSomething();
      }
    }
    

    You could of course walk further back on the call stack. But that's even more fragile because it may be a completely legal path for SomeBadObject to be on the stack when a different object calls DoSomething().

    0 讨论(0)
  • 2021-02-05 14:46

    The easiest answer would be to pass in the sender object like any event with the typical sender, eventargs methodology.

    Your calling code would look like this:

    return c.DoSomething(input, this);
    

    Your DoSomething method would simply check the type using the IS operator:

    public static int DoSomething(int input, object source)
    {
        if(source is A)
            return input + 1;
        else if(source is B)
            return input + 2;
        else
            throw new ApplicationException();
    
    }
    

    This seems like something with a little more OOP. You might consider C an abstract class with an method, and having A,B inherit from C and simply call the method. This would allow you to check the type of the base object, which is not obviously spoofed.

    Out of curiosity, what are you trying with this construct?

    0 讨论(0)
  • 2021-02-05 14:49

    Starting with Visual Studio 2012 (.NET Framework 4.5) you can automatically pass caller information to a method by using caller attributes (VB and C#).

    public void TheCaller()
    {
        SomeMethod();
    }
    
    public void SomeMethod([CallerMemberName] string memberName = "")
    {
        Console.WriteLine(memberName); // ==> "TheCaller"
    }
    

    The caller attributes are in the System.Runtime.CompilerServices namespace.


    This is ideal for the implementation of INotifyPropertyChanged:

    private void OnPropertyChanged([CallerMemberName]string caller = null) {
         var handler = PropertyChanged;
         if (handler != null) {
            handler(this, new PropertyChangedEventArgs(caller));
         }
    }
    

    Example:

    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            if (value != _name) {
                _name = value;
                OnPropertyChanged(); // Call without the optional parameter!
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-05 14:52

    structure it like a event handler, I'm sure FX cop would even suggest you do this

    static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
            {
                throw new NotImplementedException();
            }
    
    0 讨论(0)
  • There is (almost) always a proper design that can accomplish what you need. If you take one step back to describe what you actually need to do, I am confident you'll get at least one good design that doesn't require you to have to resort to something like this.

    0 讨论(0)
提交回复
热议问题