C # способ использования объектов по ссылке - PullRequest
2 голосов
/ 15 ноября 2011

Я пытаюсь выяснить этот кусок кода ASP.NET C #. Может кто-нибудь подсказать, что я тут не делаю?

Когда я запускаю приведенный ниже код, я ожидаю, что strDest будет "Новое значение", а nDest равен 2, но они останутся неизменными ...

//These are two variables to fill
string strDest = "";
int nDest = 0;

public enum MyDataType
{
    MyTypeString,
    MyTypeInt
}

public struct MyStruct
{
    public MyDataType type;
    public Object objDest;

    public MyStruct(MyDataType tType, Object oDest)
    {
        type = tType;
        objDest = oDest;
    }
}

//Pass variables by reference
MyStruct[] data2Check = {
    new MyStruct(MyTypeString, strDest),
    new MyStruct(MyTypeInt, nDest),
};

//And set them
for(int i = 0; i < data2Check.Length; i++)
{
    if(data2Check[i].type == MyTypeString)
    {
        (string)data2Check[i].objDest = "New value";
    }
    else if(data2Check[i].type == MyTypeInt)
    {
        (int)data2Check[i].objDest = 2;
    }
}

EDIT: Хорошо, позвольте мне перефразировать это. Скажем, у меня есть набор переменных или членов класса, скажем, 50 из них. Они все разных типов. (В этом примере они представлены строкой strDest и int nDest.) ОК. Теперь у меня также есть двумерный массив пар имя = значение, поэтому каждая из этих пар должна быть назначена членам моего класса в зависимости от «имени». Я делаю процесс определения, какое «имя» относится к какому-либо члену класса, и цикл for () ниже - это моя абстракция процесса присваивания. Похоже, чего не хватает, так это способа передачи моих членов класса по ссылке в цикл for (), чтобы впоследствии я мог присваивать им значения.

PS. Пока ни один из приведенных ниже примеров не справился с работой ...

Ответы [ 3 ]

3 голосов
/ 15 ноября 2011

C # не обрабатывает ссылку на значение так же, как C ++.В C # все, даже ссылки, передаются по значению по умолчанию (также: изменяемые структуры осуждаются несколькими известными разработчиками c #, включая лидера по переполнению стека Jon Skeet и руководителя команды языка C # Эрика Липперта).

Чтобы получить код, который делает то, что вы ищете, вы делаете это:

class MyStruct { /* all other code is the same, just make it a class */ }

//These are two variables to fill
MyStruct strDest = new MyStruct(MyDataType.MyTypeString, "");
MyStruct nDest = new MyStruct(MyDataType.MyTypeInt, 0);

//Pass variables by reference -- this will work now because "MyStruct" is actually a reference type
MyStruct[] data2Check = {
    strDest, //reference to actual strDest object
    nDest, //reference to actual nDest object
};

//And set them
foreach(var item in data2Check) //foreach will work instead of "for", there are some good reasons to prefer this in C#
{
    if(item.type == MyDataType.MyTypeString)
    {
        item.objDest = "New value"; // no need for a cast
    }
    else if(item.type == MyDataType.MyTypeInt)
    {
        item.objDest = 2;
    }
}

Но на самом деле вы используете некоторые идиомы из мира C ++, которые вообще не имеют смысла для C #.Придерживайтесь ссылочных типов и используйте общие, когда типы могут различаться.Я не уверен, какую именно проблему вы пытаетесь решить, или я мог бы дать вам более конкретные рекомендации о том, как выразить решение в идиоматическом c #


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

   public enum MyDataType
    {
        MyTypeString,
        MyTypeInt
    }
    public class MyStruct
    {
        public MyDataType type;
        public Object objDest;

        public MyStruct(MyDataType tType, Object oDest)
        {
            type = tType;
            objDest = oDest;
        }
    }

public partial class _Default : System.Web.UI.Page
{


    protected void Page_Load(object sender, EventArgs e)
    {
           //These are two variables to fill
            MyStruct strDest = new MyStruct(MyDataType.MyTypeString, "");
            MyStruct nDest = new MyStruct(MyDataType.MyTypeInt, 0);

            //Pass variables by reference -- this will work now because "MyStruct" is actually a reference type
            MyStruct[] data2Check = {
    strDest, //reference to actual strDest object
    nDest, //reference to actual nDest object
};

            //And set them
            foreach (var item in data2Check) //foreach will work instead of "for", there are some good reasons to prefer this in C#
            {
                if (item.type == MyDataType.MyTypeString)
                {
                    item.objDest = "New value"; // no need for a cast
                }
                else if (item.type == MyDataType.MyTypeInt)
                {
                    item.objDest = 2;
                }
            }

            Response.Write(strDest.objDest.ToString() + "<br/>" + nDest.objDest.ToString());
    }
}
1 голос
/ 15 ноября 2011

Когда вы передаете strDest и nDest конструкторам MyStruct, они передаются по значению. Сгенерированный компилятором код отличается для типа значения int и ссылочного типа string. Для значения nDest установлен бокс (это не влияет на саму переменную nDest). С string роль играет неизменность типа (или поведение «копирование при записи»).

0 голосов
/ 15 ноября 2011

Я все еще не понимаю, что вы пытаетесь сделать ... и, как говорит @JoelCoehoorn (и многие другие), вы должны попытаться сделать тип значения (struct) неизменным. Это некрасиво, но вот что работает. Если бы я лучше понимал, что вы пытаетесь сделать, это, вероятно, было бы намного чище - Я не сторонник производственного использования этого примера :

class Program
{
    static void Main(string[] args)
    {
        Foo foo = new Foo( );
        foo.Set( );

        foreach (var data in foo.data2Check)
        {
            Console.WriteLine("{0} = {1}", data.type, data.objDest);
        }

        Console.ReadKey( );
    }
}

public class Foo
{
    //These are two variables to fill
    string strDest = "";
    int nDest = 0;
    internal List<MyStruct> data2Check;

    public Foo( )
    {
        data2Check = new List<MyStruct>{
                new MyStruct(MyDataType.MyTypeString, strDest),
                new MyStruct(MyDataType.MyTypeInt, nDest),
            };
    }

    public void Set( )
    {
        //And set them
        for (int i = 0 ; i < data2Check.Count ; i++)
        {
            if (data2Check[i].type == MyDataType.MyTypeString)
            {
                data2Check[i] = new MyStruct(data2Check[i].type, "New value");
            }
            else if (data2Check[i].type == MyDataType.MyTypeInt)
            {
                data2Check[i] = new MyStruct(data2Check[i].type, 2);
            }
        }
    }
}

public enum MyDataType
{
    MyTypeString,
    MyTypeInt
}

public struct MyStruct
{
    public MyDataType type;
    public Object objDest;

    public MyStruct(MyDataType tType, Object oDest)
    {
        type = tType;
        objDest = oDest;
    }
}

Выход:

MyTypeString = Новое значение
MyTypeInt = 2

...