Click to See Complete Forum and Search --> : Using reflection to retrieve the default field value


Arjay
February 10th, 2005, 02:01 PM
Hello,
Using reflection, I'm trying to retrieve the default value for a field. In the code below, I would like to retrieve the value of 10. I can retrieve the name
of the field, its type and other meta-data, but I can't seem to retrieve the default value.

How do I do this?

Thanks,

Arjay



// Sample code from the internet
using System;
using System.Reflection;

class MyClass
{
publicint MyPublicInstanceField;
privateconstint MyPrivateConstField = 10;
}

class FieldAttributesExample
{
publicstaticvoid Main()
{
Type t = (typeof(MyClass));
string str;
FieldInfo[] fiAry = t.GetFields( BindingFlags.Static |
BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.DeclaredOnly );

foreach (FieldInfo fi in fiAry)
{
Console.WriteLine("Field {0} is: ", fi.Name);
str = ((fi.Attributes & FieldAttributes.Static) != 0) ?
"Static" : "Instance";
Console.Write(str + " ");
str = ((fi.Attributes & FieldAttributes.Public) != 0) ?
"Public" : "Non-Public";
Console.Write(str + " ");
str = ((fi.Attributes & FieldAttributes.Literal) != 0) ?
"Literal" : String.Empty;
Console.WriteLine(str);
}
}
}


The output is:

Field MyPublicInstanceField is:
Instance Public
Field MyPrivateConstField is:
Static Non-Public

Arjay
February 10th, 2005, 05:55 PM
Anyone, please?

darwen
February 10th, 2005, 06:36 PM
What do you mean by 'default value' ?

Do you mean the value which the constructor of the class initially assigns to this field ?

To do this you can either

(a) write a custom attribute and attach it to the field which reflection can then pick up

(b) create an instance of the class (assuming its constructor has no arguments) and then retrieve the value of the field using a similar reflection technique as to what you're doing.

Darwen.

Arjay
February 10th, 2005, 07:34 PM
What do you mean by 'default value' ?Thanks for answering. By 'default value', I mean the value initialized when the field (variable) is declared.

In the include sample code, for the line:

private const int MyPrivateConstField = 10;

The default value would be 10.

The 10 is what I'm looking for (or whatever value it happens to be).

darwen
February 11th, 2005, 12:46 AM
The above still applies : (a) or (b).

Darwen.

darwen
February 11th, 2005, 01:09 AM
Okay, I'm feeling generous. Try this :


public class TestClass
{
private int m_nValue = 100;

public TestClass()
{
}
}

// code
Type t = typeof(TestClass);
ConstructorInfo infoConstructor = t.GetConstructor(Type.EmptyTypes);
TestClass testClass = infoConstructor.Invoke(new object[0] { }) as TestClass;

FieldInfo[] aFieldInfo = t.GetFields( BindingFlags.Static |
BindingFlags.Instance | BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.DeclaredOnly );

foreach (FieldInfo infoField in aFieldInfo)
{
object objField = infoField.GetValue(testClass);
System.Diagnostics.Debug.WriteLine(string.Format(objField.ToString()));
}


This'll return the value of all fields after construction, providing the class has a constructor with no arguments.

As far as I know there's no way of detecting what the value is set to before the class has been instansiated. This isn't stored in the metadata : it's part of the source so you have to JIT and run the constructor first before getting the value.

This should do the trick.

Darwen.

boudino
February 11th, 2005, 01:19 AM
I see shorter solution:

Type = typeof(TestClass)
t.GetField("m_nValue", BindingFlags.Static | BindingFlags.NonPublic).GetValue(t)

and ups ... your 10 is here.

Krzemo
February 11th, 2005, 02:36 AM
and ups ... your 10 is here.U mean oops? :D

darwen
February 11th, 2005, 02:56 AM
You can't do this for non-static (or non-const) fields. You can of course do this for static fields.

And the 'foreach' loop was there because they used one.

In order to get the value of a non-static field you have to create an instance of the object first : which is I believe what I said.

And the example I gave was designed to be generic i.e. you can pass any type into it :


public class DefaultValueReflector
{
static public Hashtable GetNonStaticDefaultValues(Type type)
{
Hashtable hashFieldToValue = new Hashtable();

ConstructorInfo infoConstructor = type.GetConstructor(Type.EmptyTypes);
TestClass testClass = infoConstructor.Invoke(new object[0] { }) as TestClass;

FieldInfo[] aFieldInfo = type.GetFields( BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.DeclaredOnly );

foreach (FieldInfo infoField in aFieldInfo)
{
object objField = infoField.GetValue(testClass);
hashFieldToValue[infoField.Name, objField]
}

return hashFieldToValue;
}

static public Hashtable GetStaticDefaultValues(Type type)
{
Hashtable hashFieldToValue = new Hashtable();

FieldInfo[] aFieldInfo = type.GetFields( BindingFlags.Static | BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.DeclaredOnly );

foreach (FieldInfo infoField in aFieldInfo)
{
object objField = infoField.GetValue(type);
hashFieldToValue[infoField.Name, objField]
}

return hashFieldToValue;
}
}


If you're interested in the value of a const : why use the word "Default". "Default" implies that the value can change and so therefore can't be const.

To get the value of a field you already know the name of, then replace the 'aFieldInfo' bits with boudino's suggestion : only on the non-static one pass in the instance of the class to GetValue.

Darwen.

Darwen.

Arjay
February 11th, 2005, 09:39 AM
Thanks, everyone, I'll try it out.

Arjay