1

So I have a this class with strings, floats, DateTimes, and data tables

public class Data : IEnumerator
{

    string m_PowerSwitch = "Not Tested",
        m_SerialNumber = "Not Tested",
        m_Reset = "Not Tested",
        m_WashPump = "Not Tested",

        m_PortB = "Not Tested",
        m_PortC = "Not Tested",
        m_PortD = "Not Tested",
        m_CurlyTube = "Not Tested",
        m_BypassTube = "Not Tested";

    float m_EC53115VMeasured = 0.0F,
        m_EC53165VMeasured = 0.0F,
        m_EC531624VMeasured = 0.0F,

        m_SolventLineBVolumeMeasured = 0.0F,
        m_SolventLineCVolumeMeasured = 0.0F,
        m_SolventLineDVolumeMeasured = 0.0F,
        m_CurlyTubeVolumeMeasured = 0.0F,
        m_BypassTubeVolumeMeasured = 0.0F;
} 

I want to use a foreach statement such as

        foreach (ASM001.ASM asm in P00001.Global.ListofAvailableASMs)
        {  
            if (asm.ASMData.EndTime == null)
                asm.ASMData.EndTime = endTime;

            foreach (object data in asm.ASMData)
            {
                if (data == "Not Tested")
                {
                    asm.ASMData.Result = "FAILED";
                }
                continue;
            }

but I have not been able to find any help of searching through the individual fields of a class, just on a list of the class type.

I am getting the error foreach statement cannot operate on variables of type 'ASM001.Data' because 'ASM001.Data' does not contain a public definition for 'GetEnumerator'

I was wondering if this was possible or if I was going to have to hard code checking each string field by name and returning true or false.

And just so you now there are a lot more strings than what I copied I would have to check, which is why I was wondering if there was a quicker way to do it.

Josh Davis
  • 133
  • 9
  • shouldn't it be `IEnumerable` instead of `IEnumerator`? – DLeh Apr 13 '15 at 19:37
  • @Grant each string has a public property that excludes the m_ – Josh Davis Apr 13 '15 at 19:39
  • @DLeh it very well could be but that still doesn't solve my problem – Josh Davis Apr 13 '15 at 19:40
  • @JoshDavis well it solves the error of `does not contain a public definition for 'GetEnumerator'` – DLeh Apr 13 '15 at 19:41
  • You cannot enumerator over class fields like that. You will need to use reflection and pull the list of fields. – James Wilkins Apr 13 '15 at 19:41
  • @JamesWilkins that's not true. foreach can be used on anything that implements `IEnumerable`, doing it for a type that doesn't represent some kind of sequence of items doesn't make a whole lot of sense but it's certainly possible. To the OP you're implementing the wrong interface. The Enumator bit of it is just a small part of what's required to make a type 'foreachable' (enumberable). This might help http://stackoverflow.com/questions/11296810/how-do-i-implement-ienumerablet – evanmcdonnal Apr 13 '15 at 19:43
  • That's not what I meant. You cannot just an "IEnumerator" to a class to read its properties, nor "IEnumerable<>". You CAN, however, implement the interface methods to read the class fields if you program it to do so (but whether or not one should is another topic all together). – James Wilkins Apr 13 '15 at 19:54

3 Answers3

3

Use Reflection (code paraphrased, this will not build)

Data data = ...
Type type = data.GetType();
FieldInfo[] fields = type.GetFields(...);
foreach(FieldInfo field in fields) {

    Console.WriteLine("{0} = {1}", field.Name, field.GetValue( data ) );
}
Dai
  • 141,631
  • 28
  • 261
  • 374
  • Should have stated each field had a public property which is what I looking at but that was a simple fix and was able to figure it out from what you said – Josh Davis Apr 13 '15 at 19:52
1

From MSDN (the following example should build and run):

The following example retrieves the fields of MyClass and displays the field values.

using System;
using System.Reflection;

public class MyClass
{
    public string myFieldA;
    public string myFieldB; 
    public MyClass()
    {
        myFieldA = "A public field";
        myFieldB = "Another public field";
    }
}

public class FieldInfo_GetValue
{
    public static void Main()
    {
        MyClass myInstance = new MyClass();
        // Get the type of MyClass.
        Type myType = typeof(MyClass);
        try
        {
            // Get the FieldInfo of MyClass.
            FieldInfo[] myFields = myType.GetFields(BindingFlags.Public 
                | BindingFlags.Instance);
            // Display the values of the fields.
            Console.WriteLine("\nDisplaying the values of the fields of {0}.\n",
                myType);
            for(int i = 0; i < myFields.Length; i++)
            {
                Console.WriteLine("The value of {0} is: {1}",
                    myFields[i].Name, myFields[i].GetValue(myInstance));
            }
        }  
        catch(Exception e)
        {
            Console.WriteLine("Exception : {0}", e.Message);
        }
    }
}
Pseudonym
  • 2,052
  • 2
  • 17
  • 38
  • Wouldn't this only pull the public fields? – James Wilkins Apr 13 '15 at 19:46
  • Hmm, I am not immediately sure of that. I'll dig into it some more – Pseudonym Apr 13 '15 at 19:48
  • From the article I linked: "Access restrictions are ignored for fully trusted code. That is, private constructors, methods, fields, and properties can be accessed and invoked through reflection whenever the code is fully trusted." – Pseudonym Apr 13 '15 at 19:49
1

Possible LINQ version:

Data data = ...
FieldInfo[] fields = (from f in data.GetType().GetFields(BindingFlags.Instance|BindingFlags.NonPublic) where f.Name.StartsWith("m_") select f).ToArray();
James Wilkins
  • 6,836
  • 3
  • 48
  • 73