我想在c#中使用ref传递值,但它不像我想的那样工作
本文关键字:工作 ref | 更新日期: 2023-09-27 18:17:46
也许我想做的只是错误的方法。但我正试图写一个游戏调试打印机的东西。它是用精灵字体将值写入屏幕,用于我告诉调试器要关心的各种事情。我的调试器类很简单,但在c#中,事情似乎是通过值而不是引用传递的。所以我转向ref关键字,如果我传递正确的数据类型,它似乎可以正常工作。问题是我有这个方法签名:
Dictionary<String, object> debugStrings = new Dictionary<String, object>();
...
...
public void addVariable(String index, ref object obj) //i think it needs to be a reference, not so sure though.
{
debugStrings.Add(index, obj);
}
这将在字典中添加一个变量,最终打印到屏幕上,并为它添加一个键。
当我尝试使用上面的方法时,问题出现了:
debugPrinter.addVariable("myrotationvalue", ref this.Rotation);
根据注释中的链接,我将上面的代码更改为:
this.Rotation = 4;
object c = (object)this.Rotation;
this.Rotation = 20;
level.dbgd.addVariable("playerrot", ref c);
//always prints 4 out, i guess it still is not passing by reference?
所以它不会给出错误,但总是输出4。
我不知道我怎样才能把参考资料用起来。再次在另一个编辑中删除了参考文献:
this.Rotation = 20;
level.dbgd.addVariable("playerrot", this.Rotation);
this.Rotation = 4; //should draw to screen 4, doesn't draws 20
我显然这比我想象的要难,这将是一个简单的小有趣的课程,在我上床睡觉之前,哈哈哈…这对下周一来说不是好兆头。
完整类:
namespace GameGridTest.GameGridClasses.helpers
{
public class DebugDrawer : DrawableGameComponent
{
Dictionary<String, object> debugStrings = new Dictionary<String, object>();
int currentX;
int currentY;
VictoryGame _game;
private SpriteBatch spriteBatch;
private SpriteFont spriteFont;
public DebugDrawer(VictoryGame game) : base(game)
{
_game = game;
currentX = _game.Window.ClientBounds.Width - 400; //draw the debug stuff on right side of screen
currentY = 5;
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
spriteFont = _game.Content.Load<SpriteFont>("fonts''helpers''fpsFont");
}
public void addVariable<T>(String index, AbstractDebugHandler<T> obj) //i think it needs to be a reference, not so sure though.
{
debugStrings.Add(index, obj);
}
public void removeVariable(String index)
{
debugStrings.Remove(index);
}
protected override void UnloadContent()
{
_game.Content.Unload();
}
public override void Update(GameTime gameTime)
{
}
public override void Draw(GameTime gameTime)
{
spriteBatch.Begin();
foreach (object obj in debugStrings) //draw all the values
{
spriteBatch.DrawString(spriteFont, obj.ToString(), new Vector2(currentX, currentY), Color.White);
currentY += 30;
}
currentY = 5;
spriteBatch.End();
}
}
public abstract class AbstractDebugHandler<T>
{
public AbstractDebugHandler(T obj)
{
InnerObject = obj;
}
public T InnerObject { get; private set; }
public abstract string GetDebugString();
}
public class ThisDebugHandler: AbstractDebugHandler<object>{
public ThisDebugHandler(object innerObject) : base(innerObject){
}
public override GetDebugString(){
return InnerObject.Rotation; //??
}
}
}
你混淆了传递一个引用和通过引用传递。
形参确实是按值传递的,但这并不意味着不能传递引用类型。引用是按值传递的,这意味着引用被复制到堆栈中,对象本身没有被复制。
按引用传递在必须更改要传入的变量时使用。
只要去掉ref
关键字,你的代码就可以正常工作了。
编辑:
当您将值类型传递给方法时,它将被装箱,因此该值实际上被复制。您将显示该值的副本,而不是实时值。通过引用传递形参也没有帮助,因为您必须复制该值以使对象引用它。
如果你想显示值的类型,你宁愿发送一个函数来检索值,而不是值本身:
Dictionary<String, Func<object>> debugStrings = new Dictionary<String, Func<object>>();
public void addVariable(String index, Func<object> getValue) {
debugStrings.Add(index, getValue);
}
用法:
debugPrinter.addVariable("myrotationvalue", () => this.Rotation);
Ref将变量的指针给了另一个方法,这意味着另一个方法可以设置变量的值,而不仅仅是使用指向对象的指针。这是非常严重的!看看下面的代码:
public void Test(){
object a = new object();
Test(a);
if(a==null)
Debug.WriteLine("isNull");
else
Debug.WriteLine("isSet");
}
public void Test2(ref object obj){
obj = null;
}
你可以有相同的行为,而不是通过ref传递变量。在对象中设置valueTypes,这样可以存储指向对象的指针,而不是指向变量的指针。
例如:public abstract class AbstractDebugHandler<T>{
public AbstractDebugHandler(T obj){
InnerObject = obj;
}
public T InnerObject {get; private set;}
public abstract string GetDebugString();
}
public void addVariable<T>(String index, DebugHandler<T> obj)
{
debugStrings.Add(index, obj);
//to get debugString use
string debugValue = obj.GetDebugString();
// will always geht the current Value of the defined Object
}
在你的情况下,你必须设置"this"作为innerObject,因为旋转是一个ValueType,你必须传递包含ValueType的对象,所以两个方法"调试器"answers"callingMethod"都在同一个对象"this"上工作。DebugHandler类现在可以处理字符串转换。看到
public class ThisDebugHandler: AbstractDebugHandler<ThisType>{
public ThisDebugHandler(ThisType innerObject) : base(innerObject){
}
public override GetDebugString(){
return InnerObject.Rotation;
}
}
所以如果你现在像这样调用你的调试方法:
public void MainMethod(){
this.Rotation = 4;
ThisDebugHandler handler = new ThisDebugHandler(this);
level.dbgd.addVariable<ThisType>("someIndex",handler );
this.Rotation = 20;
//level.dbgd.print();
// now prints 20
}
我很乐意帮助你,如果还有问题请问我