19

Is it possible to get or set private fields?

I want to get System.Guid.c. Is there a way to access it or should I just copy the code from the strut and make the fields public?

budi
  • 6,351
  • 10
  • 55
  • 80
godzcheater
  • 444
  • 2
  • 5
  • 12

4 Answers4

30

You can use reflection as suggested by Quantic Programming

var guid = Guid.NewGuid();
var field= typeof (Guid).GetField("_c", BindingFlags.NonPublic |BindingFlags.GetField | BindingFlags.Instance);
var value = field.GetValue(guid);

Although if you are okay with first converting the guid to a byte array, I might suggest:

var guid = Guid.NewGuid();
var c = BitConverter.ToInt16(guid.ToByteArray(), 6);

The latter approach avoids using reflection.

Edit

You mention needing to be able to set the value as well, you can still avoid reflection:

var guid = Guid.NewGuid();
var guidBytes = guid.ToByteArray();

// get value
var c = BitConverter.ToInt16(guidBytes, 6);

// set value
Buffer.BlockCopy(BitConverter.GetBytes(c), 0, guidBytes, 6, sizeof(Int16));
var modifiedGuid = new Guid(guidBytes);
Chris Baxter
  • 16,083
  • 9
  • 51
  • 72
  • Thanks, I think it will be using the first unless there's a negative to using reflection? – godzcheater Jun 02 '12 at 14:07
  • 3
    @godzcheater - as mentioned by drf, using reflection to access private members is generally bad practise. You are using the internals of a class to access data. Where possible you should always try to stick to the public api. Reflection of private members will require a full trust environment and has the potential to be brittle code as the internals of the class may change over time. – Chris Baxter Jun 02 '12 at 14:13
6

You should try System.Reflection. Here's an example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace AccessPrivateField
{
    class foo
    {
        public foo(string str)
        {
            this.str = str;
        }
        private string str;
        public string Get()
        {
            return this.str;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            foo bar = new foo("hello");
            Console.WriteLine(bar.Get());
            typeof(foo).GetField("str", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(bar, "changed");
            Console.WriteLine(bar.Get());
            //output:
            //hello
            //changed
        }
    }
}
svick
  • 236,525
  • 50
  • 385
  • 514
Mark Segal
  • 5,427
  • 4
  • 31
  • 69
  • 1
    Just note that if you're running Silverlight, you won't be able to access the private members. You didn't specify that you were, but just in case. – Chris Sinclair Jun 02 '12 at 13:50
  • Why not? Do you mean you can't access Silverlight's internal data, or you can't do it at all when under Silverlight? – Mark Segal Jun 02 '12 at 13:52
  • 2
    With Silverlight, the runtime prevents you from accessing non-public data via reflection as it's a security issue. For example, some of the file I/O code is in the runtime, but you can normally only access it through special, managed means which do not violate security concerns. If you could use reflection to get down to the nitty-gritty of hidden file I/O, then by just browsing to a malicious Silverlight page could wipe/read your computers files at will. – Chris Sinclair Jun 02 '12 at 13:56
  • Oh, a security issue. Thanks! – Mark Segal Jun 02 '12 at 14:02
5

You can have an extension method to get any private field of any type:

public static T GetFieldValue<T>(this object obj, string name) {
    var field = obj.GetType().GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    return (T)field?.GetValue(obj);
}

And then access a private field of an arbitrary type:

Guid id = Guid.NewGuid();
Int16 c = id.GetFieldValue<Int16>("_c");
Bruno Zell
  • 7,761
  • 5
  • 38
  • 46
3

While it's possible to do this with reflection, it may be easier to simply retrieve c from System.Guid.ToByteArray().

byte[] guid = guid.ToByteArray();
short c = (short)((guid[7] << 8) | guid[6]);

Since this approach uses public and documented methods, it is less subject to change between versions. (In general, relying on private implementation details should be avoided, since these details can change from version to version.)

drf
  • 8,461
  • 32
  • 50