хочу передать значение с помощью ref в c #, но это не работает, как я думаю, что это должно - PullRequest
0 голосов
/ 12 декабря 2011

Может быть, то, что я хочу сделать, это просто неправильный способ сделать это. Но я пытаюсь написать игру для отладки принтера. Я пишу значения на экран шрифтом спрайта для разных вещей, о которых я говорю отладчику. Мой класс отладчика прост, но кажется, что в 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; //??

    }
  }
}

Ответы [ 2 ]

2 голосов
/ 12 декабря 2011

Вы путаете передачу a ссылки и передачу по ссылке.

Это правда, что параметры передаются по значению, но это не значит, что вы не можете передать ссылочный тип. Ссылка передается по значению, что означает, что ссылка копируется в стек, а сам объект не копируется.

Передача по ссылке используется, когда вам нужно изменить передаваемую переменную.

Просто удалите ключевое слово ref, и ваш код будет работать нормально.


Edit:

Когда вы передаете тип значения в метод, он будет упакован, поэтому значение будет скопировано. Вы будете отображать копию значения, а не текущее значение. Передача параметра по ссылке также не помогает, так как вам нужно скопировать значение, чтобы сделать ссылку на него объектом.

Если вы хотите отобразить типы значений, вам лучше отправить функцию, которая может извлечь значение вместо самого значения:

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 голос
/ 12 декабря 2011

Ссылка дает указатель переменной на другой метод, это означает, что другой метод может устанавливать значение переменной, а не только использовать указатель на объект. Это очень серьезно! Посмотрите на следующий код:

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;
}

Вы можете иметь такое же поведение без передачи переменной по ссылке. Поместите значение 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, чтобы оба метода «Debugger» и «callMethod» работали над одним и тем же объектом » этот". Класс 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
}

Буду рад помочь вам, поэтому, пожалуйста, спросите, если у вас есть дополнительные вопросы

...