2

I have a bunch of code that is used for debugging purposes. Therefore, I surround it with:

#if DEBUG
#endif

The issue is that this debugging code needs to output private variables from other classes to a file. I can sneak the debug code into each class but that makes existing code more confusing because I have debug code mixed with real code. I can put all the debug code into another class but that would mean that I would have to make private variables in classes public.

Is there any way to ignore the private keyword for the purposes of debugging code? I can use public getters but that defeats the purpose of not making the real code more confusing.

  • 6
    Would it be possible to make the private variables `internal` instead? – Scott Chamberlain Dec 30 '13 at 19:17
  • 1
    Do you have any unit tests? Put the debugging code in there? – SkeetJon Dec 30 '13 at 19:17
  • It's difficult for me to imagine the need for something like this. Can you provide a more complete example? It sounds like you've taken a few wrong turns already and are looking for the next wrong turn. – David Dec 30 '13 at 19:19
  • 3
    _"this debugging code needs to output private variables from other classes to a file"_ - can't you just add conditional logging _in_ that class, so each class prints its own interesting variables but only does so when logging is set to "debug"? – CodeCaster Dec 30 '13 at 19:20
  • 1
    You can use reflection to get private fields: http://stackoverflow.com/q/95910/945456. You'd have to do to use the `GetValue` method on the returned `FieldInfo` class to get the actual value. – Jeff B Dec 30 '13 at 19:22
  • @CodeCaster Yes, but two problems with that. 1) It makes the real code messier by having debug code mixed with it. 2) For some of the output, it needs private variables from multiple classes so even if I put the debug code in one class, it still wouldn't work without making variables public in other classes. – user3143211 Dec 30 '13 at 19:25
  • @ScottChamberlain Doesn't internal defeat the purpose of encapsulation? – user3143211 Dec 30 '13 at 19:27
  • There's nothing wrong perse with making private thing public, the nice way to do it is to delegate the private logic to another class and test that. – Tony Hopkinson Dec 30 '13 at 19:30
  • 1
    Yeah but what is the purpose of encapsulation, hiding the implementation, or controlling it? – Tony Hopkinson Dec 30 '13 at 19:33
  • I am trying to hide the implementation variables because I don't want real code to access those variables. The reason why I want to bypass encapsulation is for debugging purposes. The issue is that if I make it internal, then the real code now has access to variables it shouldn't have access to. – user3143211 Dec 30 '13 at 19:36
  • 1
    Sounds like a job for dependency injection – Joel Coehoorn Dec 30 '13 at 19:41
  • I would suggest to you that the benefits of good encapsulation and the costs of bad encapsulation do not magically disappear when writing debug-only code. A class should be able to output its own state to a debug file. I would also suggest that you consider using conditional methods instead of conditional compilation if you're concerned about the code looking nicer. – Eric Lippert Dec 31 '13 at 00:09

2 Answers2

2
  1. Is it possible to make them internal instead of private?
  2. Use the dynamic keyword:

    dynamic foo = yourObjectWithPrivateFields; int privateValue = (int)foo.yourPrivateField;

  3. Use Reflection: typeof(YourObject).GetField(fieldName, bindFlags).GetValue(yourObjectWithPrivateFields);

Brian
  • 5,069
  • 7
  • 37
  • 47
Florian
  • 5,918
  • 3
  • 47
  • 86
  • 1
    You can't access a private member through a variable of type `dynamic`. The only way, other than exposing some non-private member for it, is to use reflection, and have the right access. – Lasse V. Karlsen Dec 30 '13 at 19:46
1

Using Reflection as thefiloe suggests might be the best way to go for this particular problem.

Just to illustrate one way to address the code organization problem that the OP asked about, I've provided an example of an alternate approach. This may not be the ideal way to solve the problem of wanting to log data from private members for debugging purposes, but it demonstrates organizing code using partial classes as well as using a nested class in order to provide external code with a way to access private members.

    // This MyClass code goes into a MyClass.cs file
    public partial class MyClass
    {
        private int fieldA;

        private string fieldB;

        private decimal fieldC;

        public MyClass(int a, string b, decimal c)
        {
            this.fieldA = a;
            this.fieldB = b;
            this.fieldC = c;
        }
    }

    // This additional code for MyClass goes into a
    // separate MyClass.debug.cs file
#if DEBUG

    partial class MyClass : IDebugAccessible
    {
        public IDebugAccessor GetDebugAccessor()
        {
            return new DebugAccessor(this);
        }

        // The MyClass.DebugAccessor nested class has access to
        // private members of MyClass.
        private class DebugAccessor : IDebugAccessor
        {
            private MyClass instance;

            public DebugAccessor(MyClass instance)
            {
                this.instance = instance;
            }

            public IEnumerable<KeyValuePair<string, object>> Values
            {
                get
                {
                    return new Dictionary<string, object>
                    {
                        { "fieldA", instance.fieldA },
                        { "fieldB", instance.fieldB },
                        { "fieldC", instance.fieldC },
                    };
                }
            }
        }
    }

#endif

    // The intention behind creating these interfaces is to define
    // a standard way to access values from different types
    // for debugging purposes.  This is just a simple example.
    // These interfaces would go into their own .cs file.
    public interface IDebugAccessor
    {
        IEnumerable<KeyValuePair<string, object>> Values { get; }
    }

    public interface IDebugAccessible
    {
        IDebugAccessor GetDebugAccessor();
    }
Dr. Wily's Apprentice
  • 10,212
  • 1
  • 25
  • 27