Как получить доступ к существующим объектам со строковым вводом (Преобразовать строковый ввод в имя объекта)

Я создаю много объектов под названием: Obj1, Obj2.... ObjX

Object Obj1 = new Object();
Object Obj2 = new Object();
Object ObjX = new Object();

Теперь у меня есть функция, где я хочу получить доступ к одному из этих объектов.

public void useObject(int objectNumber) {
     String objectName = "Obj" + objectNumber;
     objectName.doAnythingWithThisObject();
     }

Возможно ли что-то подобное в C# или Java? Я не хочу использовать что-то вроде:

switch(objectNumber) {
      case 1: 
        Obj1.doThis();
       break;
      case 2: 
        Obj2.doThis();
       break;

Если бы я использовал switch / if-else, я должен был бы повторить много кода, который делает эту вещь менее читаемой, потому что я должен вызывать одну и ту же функцию с разными объектами.

4 ответа

Решение

Фактический ответ таков: вы вообще не должны обращаться к своим переменным, используя строки во время выполнения. Случаев, когда это действительно уместно, мало и далеко друг от друга, и ваш пример, хотя и упрощенный, но может использоваться только для иллюстрации, не очень подходит для этого.

Вместо этого, почему бы вам просто не использовать коллекцию или массив для хранения ваших объектов? @TRRohith приводит пример в своем ответе.

Тем не менее, прямой ответ на ваш вопрос, в том, что касается Java, приведен ниже. Хотя код для C# будет другим, языковая функция, которая может использоваться для этой цели, а именно рефлексия, также доступна в C#.


Если Obj1, Obj2 и т. д. объявляются как статические или экземпляры полей в классе, вы можете получить их значения по их именам, используя отражение (см. соответствующие документы для Java). Если они являются локальными для метода, простого способа сделать это не существует (см. Эти вопросы: для Java, для C#).

Статические поля

class Something {
    static Object obj1 = new Object();
    static Object obj2 = new Object();
    // etc.
}

(Я взял на себя смелость начинать имена полей строчными буквами, как это принято в Java.)

В этом случае вы можете получить значение переменной по ее имени, используя следующий код (вам нужно импортировать java.lang.reflect.Field):

// Get field, named obj1, from class Something.
Field f = Something.class.getDeclaredField("obj1");
// This line allows you access the value of an inaccessible (non-public) field.
f.setAccessible(true);
// Assigning the value of the field, named obj1, to obj.
// You may want to cast to a more concrete type, if you know exactly what is stored in obj1.
// The parameter for get() is ignored for static fields, so simply pass null.
Object obj = f.get(null);

// Now you can do whatever you want with obj, 
// which refers to the same object as static field obj1 of Something.
System.out.println(obj);

Поля экземпляра

class Something {
    Object obj1 = new Object();
    Object obj2 = new Object();
    // etc.
}

Вы можете сделать это почти так же, как для полей экземпляра, вам просто нужен экземпляр класса для передачи f.get(), Итак, для примера, давайте предположим, что у нас есть экземпляр класса Something, называется sth,

// Let's say this is an instance of our class
Something sth = new Something();
// ...

// Get field, named obj1, from class Something.
Field f = Something.class.getDeclaredField("obj1");
// This line allows you access the value of an inaccessible (non-public) field.
f.setAccessible(true);
// Assigning the value of the field, named obj1, to obj.
// You may want to cast to a more concrete type, if you know exactly what is stored in obj1.
// The parameter for get() is the instance of Something, 
// for which you want to retrieve the value of an instance field, named obj1.
Object obj = f.get(sth);

// Now you can do whatever you want with obj,
// which refers to the same object as instance field obj1 of sth.
System.out.println(obj);

Локальные переменные

Вам, вероятно, не повезло в этом случае. Опять же, смотрите следующие ссылки: Java, C#.

Вот код:

    //Declare this in the class so that it can be called by any method
static Object[] array = new Object[4];
public static void main()
{
    //Use this to initialize it
    Object[] array = new Object[4];
    for(int i=0;i<4;i++)
    {
        array[i] = new Object();
    }
    //You can now easily call it
    useObject(0);
    useObject(1);
    useObject(2);
    useObject(3);
}

//Your numbers may be off by 1 because we are using an array but that is easily adjusted
public static void useObject(int objectNumber)
{
    array[objectNumber].doAnythingWithThisObject();
}

Это звучит как классическая проблема Стратегии.

Ответ... нет. Вместо этого используйте массив. Это именно то, для чего они.

ObjectType[] objectArray = new ObjectType[10]; // Or as many as required.
for (int i = 0; i < objectArray.length; i++) {
    objectArray[i] = new ObjectType(); // Or whatever constructor you need.
}

// Then access an individual object like this...
ObjectType obj = objectArray[4];

// Or...
objectArray[5].someMethod();
Другие вопросы по тегам