我可以通过引用传递对象吗
本文关键字:对象 可以通过 引用 | 更新日期: 2023-09-27 18:19:34
我正试图将一个对象从xna游戏传递到我正在编写的xna游戏库中的方法中。对象基本上可以是任何类型,包括引用类型和值类型。
游戏库用于调试目的,应该将传入对象的当前值打印到屏幕上。它目前通过调用对象上的ToString
来实现这一点,但将来字符串将根据底层类型进行格式化。
以下是接收参数的游戏库方法
public void AddToDebug(object obj)
{
var type = obj.GetType();
_debugTypes.Add(obj, type);
}
这里有一个在主游戏项目中使用它的例子
VD.AddToDebug(_counter);
VD.AddToDebug(_message);
_counter
是一个int,_message
是一个字符串。
问题是,这些值的变化不会反映在屏幕上,因为(我认为)它们是通过值传递的,而不是通过引用传递的。
我尝试添加ref关键字以确保它们通过引用传递,但这会在调用The ref argument type does not match parameter type
的方法中导致错误
有没有一种方法可以通过引用传递值类型,而不必指定实际类型(如果可以避免的话,我不想为所有值类型创建方法重载)。
也欢迎任何其他建议。感谢
更新
在尝试了几种不同的方法后,我最终决定采用一种简单的方法,将Func<T>
传递到AddToDebug
方法中,如下所示。我意识到,至少目前,我不需要底层值,只需要它的格式化字符串表示
将来我可能会扩展库以自动扫描传入类型并显示其所有成员的值。如果涉及到这一点,我可能会使用@Hans Passant的建议来传递对有问题的班级的引用。
也就是说,我将接受@Lee的回答,因为它在我的最终实现中最有用,建议使用Func
。
这是我现在拥有的代码,欢迎任何改进建议。谢谢大家的帮助。
public void AddToDebug<T>(Func<T> getValue, Color? color = null)
{
var w = new DebugEntry<T>(getValue, color.HasValue ? color.Value : Color.White);
_values.Add(w);
}
public class DebugEntry<T> : IStringFormatter
{
private readonly Func<T> _getValue;
public Color Color { get; private set; }
public DebugEntry(Func<T> getValue, Color color)
{
_getValue = getValue;
Color = color;
}
public string ToFormattedString()
{
return _getValue.Invoke().ToString();
}
}
public interface IStringFormatter
{
string ToFormattedString();
Color Color { get; }
}
// Example usage
VD.AddToDebug(() => _counter);
VD.AddToDebug(() => String.Format("This message says {0} times", _message));
您的int
不存在于堆中,因此无法创建对它的永久引用。ref
引用只存在于被调用函数返回之前(以保护内存安全)。您想要的是创建对存储int
的位置的引用。最好的选择可能是创建一个包装类并在堆上实例化它:
class Box<T> { public T Value; }
您可以传递对该类实例的引用,并且每个拥有该引用的人都可以读取和写入该值。
_counter是一个int,_message是一个字符串。
哪些.NET类型会破坏您的计划。int是一种值类型,当您将其传递给接受对象类型参数的方法时,int将被装箱。您将获得该值的副本。无论你做什么,更新副本都不会对原始值产生影响。
类似于字符串,它是一个不可变的引用类型。它不能以任何方式更改,只能从原始字符串对象创建新字符串对象。一个新的字符串,当然原始代码对此一无所知。
要使更新在其他代码中可见,需要指针。指针是相当棘手的,C#很好地支持它们,但创建一个指向变量的指针有很多陷阱。例如,您永远不能创建指向局部变量的指针,并期望该指针在方法退出时仍然有效。局部变量已不存在。无论如何,通过指针更新值都会损坏内存。使用指针时需要使用unsafe关键字的一个重要原因。
指针已经被巧妙地封装在C#中,它们被称为引用。和在创建引用类型的对象时自动使用。因此,您应该做的不仅仅是传递简单的值或字符串,而是传递对对象的引用。类对象。现在,调试代码和原始代码都使用了对完全相同对象的引用。对其中一个对象的字段和属性所做的更新对另一个对象可见。
听起来你想要一种包装变量的方法,而不是获取其当前值。
您可以创建一个包装器,每次调用ToString
时都会获取当前值,然后从包含类传递一个委托来获取变量:
public class Wrapper<T>
{
private readonly Func<T> getter;
public Wrapper(Func<T> getter)
{
this.getter = getter;
}
public override string ToString()
{
return getter().ToString();
}
}
然后在你的课堂上:
AddToDebug(new Wrapper<int>(() => this.intField));