简体   繁体   中英

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

I'm trying to create something like a pool of exemplar's class and use its methods.

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];
    }
}

Here is an example of some class, what i have to create in pool

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

and then I try to use it like this

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

But it's haven't seen a method, because return type — object. I have try to convert object[] to Type, but i get "object must implement iconvertible" exception.

Maybe there are some easy and simple ways to initialize object[] like this:

object = new (type)[object_count]

or something else?

Thanks for your answers!

Yes, you can. The syntax you've predicted is very similar.

An array can have a type of the objects it's containing:

T[] array = new T[size];

where T is the type (class, struct) you want the array to hold. Based off your code in your case it would be InstanceCreation .

It would be a nice time to tackle with C# Generics for you. Take a look at System.Collections.Generic.List<T> .

You can indeed "Cast" your object to a specific type.

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

But in this case I would recommend using Generics. Creating generic methods can be a bit complex in some cases - luckily I do not believe this is one of them.

With generics you do not have to change everything to an "object" and the compiler can keep track of the types for you. This will allow it to show a number of errors you have in your code.

To give you a starting point to work from, I have tried changing your object pool class into a generic implementation here. I added comments for things I changed and things you still need to work on. Notice I did not run this, just checked no error is highlighted in Visual Studio, so there might still be a few things you need to change once you start debugging. :)

// 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];
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM