我正在尝试将数组传递给方法。该数组包含需要为空的对象。该方法将简单地使循环中的每个对象为空。我需要这个反映在来电者身上。
示例代码(可以忽略代码优度和次要语法问题):
public class ABC
{
...
}
private void SomeMethod()
{
var toBeNulledObj1 = new ABC();
var toBeNulledObj2 = new ABC();
var arrayOfNullableObjects = new ABC[]{toBeNulledObj1 ,toBeNulledObj2};
NullingFunction(arrayOfNullableObjects);
}
private void NullingFunction(ABC[] arrayOfNullableObjects)
{
for(int i = 0; i< arrayOfNullableObjects.Length ; i++)
{
arrayOfNullableObjects[i] = null;
}
}
返回后,toBeNulledObj1
&amp;虽然toBeNulledObj2
现在有两个arrayOfNullableObjects
个对象,但null
不是null但保留其旧值。我意识到ref&amp; out仅适用于collection参数(此处,arrayOfNullableObjects
甚至不需要ref)。我尝试将它们作为params
而不是集合传递,但这也无济于事(参考和参数不能合并)。
问题:如何更改方法中对象集合中的每个/任何对象,以使调用者可以看到更改?我不是在改变收藏本身。请注意,我没有更改toBeNulledObj1
的内容/成员,而是更改引用本身(无论是null还是新对象)。
答案 0 :(得分:2)
一种解决方案是使用不安全的代码。在使用它之前你必须要三思而后行,我不知道你是否对我的答案感到满意,但现在就是。
static private void SomeMethod()
{
ABC toBeNulledObj1 = new ABC();
ABC toBeNulledObj2 = new ABC();
IntPtr[] arrayOfNullableObjects = new IntPtr[] { MakeReference(ref toBeNulledObj1), MakeReference(ref toBeNulledObj2) };
NullingFunction(arrayOfNullableObjects);
}
static private void NullingFunction(IntPtr[] arrayOfNullableObjects)
{
foreach (IntPtr reference in arrayOfNullableObjects)
ClearReference(reference);
}
/// <summary>
/// Makes the reference to the reference value of a reference type.
/// </summary>
static unsafe private IntPtr MakeReference<T>(ref T value)
where T: class
{
TypedReference reference = __makeref(value);
return *(IntPtr*)&reference;
}
/// <summary>
/// Clears the reference to a reference type, using a reference to that reference value.
/// </summary>
static unsafe private void ClearReference(IntPtr reference)
{
if (sizeof(IntPtr) == 4)
*((int*)reference) = 0;
else
*((long*)reference) = 0;
}
第二种解决方案可以通过使用保存数据的匿名类来完成。此匿名类中的字段已清除。缺点是你有第二个类,也应该清除对这个类的引用。 (这可以通过将ref
添加到o
和NullingFunction
集o
添加到null
来完成。)当然,您也可以使用预定义的类,但他的解决方案最接近你的OP中的代码。
public static void SomeMethod()
{
var container = new
{
toBeNulledObj1 = new ABC(),
toBeNulledObj2 = new ABC(),
};
NullingFunction(container);
}
private static void NullingFunction<T>(T container)
where T : class
{
if (container == null)
return;
foreach(FieldInfo f in container.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
if (f.FieldType.IsClass)
f.SetValue(container, null);
}
答案 1 :(得分:1)
当您说要将它们设置为null时,是否意味着要销毁该对象?
C#具有自动垃圾收集功能,因此只要对象超出范围(即没有其他对象引用它),垃圾收集器就会销毁它。
在上面的代码中,标签“tobeNulledObj1”仍然引用一个对象,并且在调用NullingFunction之前,您的数组也指向它。
调用NullingFunction后,仍然有一个指向对象的引用(即tobeNulledObj1)。如果将toNulledObj1设置为null,则垃圾收集器将收集它。
编辑:我第二个cheedep的问题 - 你究竟想要做什么?你希望你的变量在最后得到什么?答案 2 :(得分:0)
如果函数A包含对变量的引用,即:
var toBeNulledObj1 = new ABC();
var toBeNulledObj2 = new ABC();
并没有将其传递给功能B:
private NullingFunction(ABC[] arrayOfNullableObjects)
然后有 nothing ,函数B可以更改toBeNulledObj1 / 2指向的引用。
由于ref不允许与params一起使用(如你所提到的):
private void NullingFunction(ref params ABC[] arrayOfNullableObjects)
{
for (int i = 0; i < arrayOfNullableObjects.Length; i++)
{
arrayOfNullableObjects[i] = null;
}
}
可用的替代方法是创建重载,例如:
private void SomeMethod()
{
var toBeNulledObj1 = new ABC();
var toBeNulledObj2 = new ABC();
NullingFunction(ref toBeNulledObj1, ref toBeNulledObj2);
Console.ReadKey();
}
private void NullingFunction(ref ABC one)
{
one = null;
}
private void NullingFunction(ref ABC one, ref ABC two)
{
one = null;
two = null;
}
答案 3 :(得分:0)
包装是否可以接受?
class Wrapped<T> where T : new() {
private T val = new T();
...
public void Nullify() { val = null; }
}
private void SomeMethod()
{
var toBeNulledObj1 = new Wrapped<ABC>();
var toBeNulledObj2 = new Wrapped<ABC>();
var arrayOfNullableObjects = new Wrapped<ABC>[]{toBeNulledObj1 ,toBeNulledObj2};
NullingFunction(arrayOfNullableObjects);
Debug.Assert(toBeNulledObj1.Get() == null);
// Or...
Debug.Assert(toBeNulledObj1.IsDefined == false);
// Or...
Debug.Assert(toBeNulledObj1.IsNull == true);
}
private void NullingFunction(Wrapped<ABC>[] arrayOfNullableObjects)
{
for(int i = 0; i< arrayOfNullableObjects.Length ; i++)
{
arrayOfNullableObjects[i].Nullify();
}
}
(免责声明:手工编译的代码:)可能包含错误)
如果您需要它作为一般模式,您可以使用constaint where U: Wrapped<T>
如果您熟悉C ++,那么想法是为ref类型创建类似于Nullable
的东西,或者看起来像智能指针的东西。
因此,包装器可以T Get()
(或隐式转换为T)来获取值,IsDefined
属性,等等。