如果 class 的类型未知,如何创建 class 样本数组并使用它们的方法

How to create array of class exemplars and use their methods if type of class is unknown

我正在尝试创建类似范例池的东西 class 并使用它的方法。

public class PoolOfObjects
{
    public delegate Object InstanceCreation();
    public Object[] objects;
    bool?[] State;
    InstanceCreation _creator;
    Type _type;

    public PoolOfObjects(Type type, int objects_count, InstanceCreation creator)
    {
        objects = new object[objects_count];
        State = new bool?[objects_count];
        for (int i = 0; i < objects_count; i++)
            objects[i] = _creator;
    }

    //Must return an exemplar by state of object when called 
    public Object EjectObject (bool? state)
    {
        int i;
        for (i = 0; i < State.Length; i++)
            if (State[i] == state)
            { //create object if null
                if (objects[i] == null)
                    objects[i] = _creator;
                break;
            }
        return objects[i];
    }
}

这是一些 class 的示例,我必须在池中创建的内容

public class Test
{
    public Test()
    {
        Console.WriteLine("constructor");
    }
    public void SomeMethod()
    {
        Console.WriteLine("SomeMethod");
    }
}

然后我尝试这样使用它

PoolOfObjects pool = new PoolOfObjects(typeof(Test),27,delegate {
            return new Test();
        });
pool.EjectObject(null).SomeMethod();

但它还没有看到一个方法,因为return type — object。我尝试将 object[] 转换为 Type,但出现 "object must implement iconvertible" 异常。

也许有一些像这样初始化object[]的简单方法:

object = new (type)[object_count]

还是别的?

感谢您的回答!

是的,你可以。您预测的语法非常相似。

数组可以具有它包含的对象的类型:

T[] array = new T[size];

其中 T 是您希望数组保存的类型(class,结构)。根据您的代码,您的情况将是 InstanceCreation.

现在是解决 C# 泛型问题的好时机。看看System.Collections.Generic.List<T>.

您确实可以 "Cast" 您的对象到特定类型。

object stringAsObject = "This is a string";
string stringAsString = (string)stringAsObject;

但在这种情况下,我建议使用泛型。在某些情况下,创建泛型方法可能有点复杂 - 幸运的是,我认为这不是其中之一。

使用泛型,您不必将所有内容更改为 "object",编译器可以为您跟踪类型。这将允许它显示您的代码中的许多错误。

为了给您一个工作起点,我尝试将您的对象池 class 更改为此处的通用实现。我为我更改的内容和您仍需要处理的内容添加了评论。请注意,我没有 运行 这个,只是检查 Visual Studio 中没有突出显示错误,因此一旦开始调试,您可能仍然需要更改一些内容。 :)

// Changed to Generics. This makes the class easier to use.
public class PoolOfObjects<T>
{
    // Changed to private - you do not want this accessible from the outside
    // Changed the type to T so you do not have to cast.
    private T[] _objects;

    // Changed to prefix with _. 
    // Not all coding guidelines do this, but whatever you do be consistent.
    // Changed to states as there appears to be on per object.
    private bool?[] _states;

    // Using the standard Func<T> (function returning T)
    // instead of introducing a new delegate type
    private Func<T> _creator;

    // Changed to camelCase and Func<T> instead of custom delegate
    public PoolOfObjects(int objectsCount, Func<T> creator)
    {
        // Changed to remember the creator
        _creator = creator;
        // I left this an array, but consider changing to List<T>,
        // then the list can grow as needed. 
        _objects = new T[objectsCount];
        _states = new bool?[objectsCount];

        // removed initialization of objects
        // as it appears you do it when calling EjectObject
    }

    //Must return an exemplar by state of object when called 
    public T EjectObject(bool? state)
    {
        // TODO:
        // You never assign any values to the _states array,
        // so it will always have the value null.
        // this means if your method is called with true or false,
        // it will FAIL!
        // I do not know what "states" is for so I can't suggest how to fix it.

        // If it is to track if an object is already in use I recommend getting
        // rid of it and change your _objects to be:
        //   private Queue<T> _objects
        // Then this method will check if there are any items in the _objects queue,
        // if there is dequeue one and return it. If not, create a new object
        // and return it.
        // You then need to create another method to put the items back in the queue
        // after use.

        int i;
        for (i = 0; i < _states.Length; i++)
            if (_states[i] == state)
            { //create object if null
                if (_objects[i] == null)
                    // Changed to call your creator instead of assigning it.
                    _objects[i] = _creator();
                break;
            }
        // TODO: Your program will crash with an unclear error here if no object
        // has a state matching the requested state.
        return _objects[i];
    }
}