[SalesForce] Iterate over a dynamically populated list of objects

I have a SOQL query where I don't know the FROM object, meaning it can change every time. So I dynamically populate it like so

// dynamicObject is a String.

    String queryString = 'SELECT '
                            + ' Id, Name ' +
                            + ' FROM ' + dynamicObject;
    List<sObject> sourceObjects;
// Downcasting from a generic list of sobjects to the particular type of the object.
    sourceObjects = (List<SObject>)Type.forName('List<' + dynamicObject + '>').newInstance();
    sourceObjects = Database.query(queryString);

As you can see I am downcasting from a generic sObject type to a specific one. I used this solution: Dynamically assign the dataType of a Set

However now I am trying to iterate over this list of results and the only way I can iterate is if I use the SObject type which does not recognize the Name field I queried for.

I tried doing something like this:

SObject dynamicType = (SObject)Type.forName(dynamicObject).newInstance();

for(dynamicType obj: sourceObjects) {
    //something
}

However that comes back as Invalid type: dynamicType.

Is there a way to iterate over the List where I will be able to reference the Name field that's part of the query?

Best Answer

You can simply use sObject.get() to dynamically reference the field by name.

for(sObject obj: sourceObjects) {
    doSomeWork((String)obj.get('Name'));
}

Apex doesn't have the kind of type-level dynamism you're trying to use here, and it's probably useful to make a distinction between the compile-time type that's declared for a variable, and the runtime type of an actual value you assign to it.

For example, when you do this:

sourceObjects = (List<SObject>)Type.forName('List<' + dynamicObject + '>').newInstance();
sourceObjects = Database.query(queryString);

you're not affecting the compile-time type of sourceObjects. The cast only affects the value that you're assigning to that variable. In this case, the value that you assign is immediately replaced when you perform

sourceObjects = Database.query(queryString);

in the following line, but it wouldn't affect the variable's type in any case.

Likewise, when you do

SObject dynamicType = (SObject)Type.forName(dynamicObject).newInstance();

you're getting a concrete instance of that dynamically determined type, but the variable dynamicType still has the compile-time type SObject - assigning it a value whose (runtime) type is an sObject subclass doesn't change the compile-time type of the variable.

It also doesn't give you a reference to the type itself that you can use to declare other variables; you can't actually declare a variable with a dynamically-determined type like that.