如果 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];
}
}
我正在尝试创建类似范例池的东西 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];
}
}