How to use reflection & Enums in C# 2.0

S

Shmuel Cohen

I have a class holding some enumerated types, i.e.,

public class MyEnums
{
public enum DATA_ITEM {FIRST, SECOND, THIRD,FOURTH,FIFTH};
...
}

And I have a class the contains data, for example:

public class TheData
{
double a, b, c;
int d,e;

...
}


public class MyDataClass
{
List<TheData> myData;

public List<TheData> MYDATA
{
get {return myData; }
...
}
...
}


I want to write a utility function as follows

public class Utility {

private double adder (List<TheData> data, FIELD fld) --> ???
{
double val = 0.0;
foreach (...)
{
val += data.fld; --> ????
}
}
public static SUM_DATA (MyDataClass mdc, MyEnums.DATA_ITEM di)
{

// Determine the field to sum up
switch (di)
{
case MyEnums.DATA_ITEM.FIRST:
return adder (mdc.MYDATA, FIELD a); --> ????

case MyEnums.DATA_ITEM.SECOND:
return adder (mdc.MYDATA, FIELD b); --> ????


}
}

Basically, I want to get the field to add up, and pass this information
to the private "adder" function, along with the
proper field to use - I'd like to avoid summing up the items in a
switch() statement because each data array is quite large.

Any ideas on how to properly implement this?

Thanks!
 
D

Derrick Coetzee [MSFT]

Hi! I edited your code to fit it in a smaller space for easier viewing,
but it shouldn't change the concepts.

Shmuel said:
public class MyEnums {
public enum DATA_ITEM {FIRST,SECOND,THIRD,FOURTH,FIFTH};
}

public class TheData { public double a, b, c; }

public class Utility {
private static double adder (TheData data, FIELD fld) {
double val = 0.0;
val += data.fld;
}
public static double SUM_DATA (TheData mdc, MyEnums.DATA_ITEM di) {
switch (di) {
case MyEnums.DATA_ITEM.FIRST:
return adder (mdc, FIELD a);
case MyEnums.DATA_ITEM.SECOND:
return adder (mdc, FIELD b);
}
return 0.0;
}
}

The simplest way to accomplish this is to use reflection. Given a string
name, you can retrieve the field with that name and type FieldType from
object obj with the following expression:

(FieldType)obj.GetType().GetField(name).GetValue(obj)

Here it is in your example:

public class Utility {
private static double adder (TheData data, string fld) {
double val = 0.0;
val += (double)data.GetType().GetField(fld).GetValue(data);
return val;
}
public static double SUM_DATA(TheData mdc, MyEnums.DATA_ITEM di) {
switch (di) {
case MyEnums.DATA_ITEM.FIRST:
return adder (mdc, "a");
case MyEnums.DATA_ITEM.SECOND:
return adder (mdc, "b");
}
return 0.0;
}
}

If you find the syntax annoyingly verbose, you may find the following
class I whipped up helpful:

public class FieldReflector
{
private Object _obj;

public FieldReflector(Object obj)
{
_obj = obj;
}

public Object this[string name]
{
get
{
return _obj.GetType().GetField(name).GetValue(_obj);
}
set
{
_obj.GetType().GetField(name).SetValue(_obj, value);
}
}
}

Now you can simply do this:

private static double adder (TheData data, string fld)
{
FieldReflector datafr = new FieldReflector(data);
double val = 0.0;
val += (double)datafr[fld];
return val;
}

However, reflection can have a significant performance cost, so be
careful not to use it extensively in performance-critical paths.
Instead, you may wish to simply use an array of instance variables and
access them using properties:

public class TheData
{
public double[] fields = new double[3];
public double a
{
get { return fields[0]; }
set { fields[0] = value; }
}
public double b
{
get { return fields[1]; }
set { fields[1] = value; }
}
public double c
{
get { return fields[2]; }
set { fields[2] = value; }
}
public enum FieldNames { A, B, C }
}

public class Utility
{
private static double adder (TheData data, TheData.FieldNames fld)
{
double val = 0.0;
val += (double)data.fields[(int)fld];
return val;
}
}

Please ask if any of this is unclear to you. I hope this helps.
 
S

Shmuel Cohen

Derrick,

Awesome! Great explanation - just what I was looking for - thanks a
million!


Derrick Coetzee said:
Hi! I edited your code to fit it in a smaller space for easier viewing,
but it shouldn't change the concepts.

Shmuel said:
public class MyEnums {
public enum DATA_ITEM {FIRST,SECOND,THIRD,FOURTH,FIFTH};
}

public class TheData { public double a, b, c; }

public class Utility {
private static double adder (TheData data, FIELD fld) {
double val = 0.0;
val += data.fld;
}
public static double SUM_DATA (TheData mdc, MyEnums.DATA_ITEM di) {
switch (di) {
case MyEnums.DATA_ITEM.FIRST:
return adder (mdc, FIELD a);
case MyEnums.DATA_ITEM.SECOND:
return adder (mdc, FIELD b);
}
return 0.0;
}
}

The simplest way to accomplish this is to use reflection. Given a string
name, you can retrieve the field with that name and type FieldType from
object obj with the following expression:

(FieldType)obj.GetType().GetField(name).GetValue(obj)

Here it is in your example:

public class Utility {
private static double adder (TheData data, string fld) {
double val = 0.0;
val += (double)data.GetType().GetField(fld).GetValue(data);
return val;
}
public static double SUM_DATA(TheData mdc, MyEnums.DATA_ITEM di) {
switch (di) {
case MyEnums.DATA_ITEM.FIRST:
return adder (mdc, "a");
case MyEnums.DATA_ITEM.SECOND:
return adder (mdc, "b");
}
return 0.0;
}
}

If you find the syntax annoyingly verbose, you may find the following
class I whipped up helpful:

public class FieldReflector
{
private Object _obj;

public FieldReflector(Object obj)
{
_obj = obj;
}

public Object this[string name]
{
get
{
return _obj.GetType().GetField(name).GetValue(_obj);
}
set
{
_obj.GetType().GetField(name).SetValue(_obj, value);
}
}
}

Now you can simply do this:

private static double adder (TheData data, string fld)
{
FieldReflector datafr = new FieldReflector(data);
double val = 0.0;
val += (double)datafr[fld];
return val;
}

However, reflection can have a significant performance cost, so be careful
not to use it extensively in performance-critical paths. Instead, you may
wish to simply use an array of instance variables and access them using
properties:

public class TheData
{
public double[] fields = new double[3];
public double a
{
get { return fields[0]; }
set { fields[0] = value; }
}
public double b
{
get { return fields[1]; }
set { fields[1] = value; }
}
public double c
{
get { return fields[2]; }
set { fields[2] = value; }
}
public enum FieldNames { A, B, C }
}

public class Utility
{
private static double adder (TheData data, TheData.FieldNames fld)
{
double val = 0.0;
val += (double)data.fields[(int)fld];
return val;
}
}

Please ask if any of this is unclear to you. I hope this helps.
--
Derrick Coetzee, Microsoft Speech Server developer
This posting is provided "AS IS" with no warranties, and confers no
rights. Use of included code samples are subject to the terms
specified at http://www.microsoft.com/info/cpyright.htm
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top