想在c#中使用ref传递值,但它不像我认为的那样工作

时间:2011-12-12 07:18:28

标签: c# types casting xna

也许我想要做的只是走错路。但我正在尝试编写游戏调试打印机的东西。它是以精灵字体为屏幕写入值,用于告诉调试器要关心的各种事情。我的调试器类很简单,但似乎在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);                        
    }

这会在字典中添加一个变量,最终打印到屏幕上,并附带一个密钥,以便将其称为。<​​/ p>

当我尝试使用上述方法时会出现问题:

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; //??

    }
  }
}

2 个答案:

答案 0 :(得分:2)

您难以通过 引用并通过引用传递

参数是按值传递的,但这并不意味着您无法传递引用类型。引用按值传递,这意味着引用被复制到堆栈,对象本身不会被复制。

当您必须更改要传入的变量时,将使用按引用传递。

只需删除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);

答案 1 :(得分:1)

Ref将变量的指针赋给另一个Method,这意味着另一个方法可以设置变量的值,而不仅仅是使用指向对象的指针。这非常严重!看看下面的代码:

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,因为Rotation是一个ValueType,你必须传递包含ValueType的Object,所以方法“Debugger”和“callingMethod”都在处理同一个对象“这个”。 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
}

很乐意帮助您,所以请询问您是否还有其他问题