【问题标题】:C# way to use Objects by referenceC#通过引用使用对象的方法
【发布时间】:2011-12-29 05:19:56
【问题描述】:

我正在尝试找出这段 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;
    }
}

编辑: 好的,让我重新措辞一下。比如说,我有一组变量或一个类的成员,比如 50 个。它们都是不同的类型。 (在本例中,它们由字符串 strDest 和 int nDest 表示。)好的。现在我还有一个 name=value 对的二维数组,所以这些对中的每一个都应该根据“名称”分配给我的班级成员。我执行确定哪个“名称”归类的哪个成员的过程,下面的 for() 循环是我对分配过程的抽象。似乎缺少的是通过引用将我的类成员传递到这个 for() 循环的方法,以便我以后可以为它们分配值。

PS。到目前为止,下面的例子都没有完成这项工作......

【问题讨论】:

  • 您是否在回发后运行此程序?您是否意识到您正在为每个回发/事件使用页面类的全新实例,而不是同一个实例?
  • 另外,您的代码示例没有显示您在哪里观察到的结果,或者您期望观察到的内容与实际观察到的内容。
  • 不,这与回发与否无关。这一切都在一个功能中。它是 C# 语言。正如您可能知道的那样,我来自 C/C++ 世界,在那里我会使用 & 运算符通过引用传递对象,但在 C# 中这似乎不起作用。这就是我在...中寻求帮助的原因。
  • 结果在 for() 循环运行结束的这个块的末尾
  • 您在帖子中提到了 ASP.NET。与 ASP.NET 相关的上下文中有哪些内容?你在你的页面上打印它吗?或者它是否发生在页面上的某个事件上(回发)?

标签: c# asp.net object pass-by-reference


【解决方案1】:

C# 处理引用与值的方式与 C++ 不同。在 C# 中,所有内容,甚至引用,都默认按值传递(另外:可变结构被一些著名的 c# 开发人员所反对,包括堆栈溢出代表负责人 Jon Skeet 和 C# 语言团队负责人 Eric Lippert)。

要获得符合您要求的代码,请执行以下操作:

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

【讨论】:

  • 谢谢。我得先检查你的代码。我正在尝试做的是解析文本,然后从参数=值对中设置一个类中的一堆变量(大约 50 个),因此是这样的构造。
  • 在这种情况下,惯用的 C# 是只有一个类的私有构造函数和一个公共静态 .Create() 或 .Load() 方法,该方法将流读取器的引用作为参数并返回对象的一个​​新实例(该静态方法将能够调用私有构造函数)。类的所有属性都不应该是“对象”类型,但如果您不知道要提前加载什么,您可以选择使用 Dictionary
  • 不,它仍然不起作用。对不起。为什么我不能将 MyStruct 类/结构的成员声明为 public ref Object objDest?
  • 当然可以。这段代码可以满足您的要求。如果你把它放在一个控制台应用程序中,并在循环之后输出 strDest.objDest 和 nDest.objDest 的值,你会看到“新值”和“2”。使用复制/粘贴来编写代码是否是在帮自己一个忙是另一回事。
  • 轻微更正:Ed Maurer 是语言开发团队的负责人。我只是团队中的一个人。
【解决方案2】:

当您将strDestnDest 传递给MyStruct 构造函数时,它们是按值传递的。对于值类型int 和引用类型string,编译器生成的代码是不同的。对nDest 的值进行了装箱(这不会​​影响nDest 变量本身)。对于string,它是类型不变性(或“写入时复制”行为)发挥作用。

【讨论】:

  • 谢谢。那么有什么方法可以调整它,以便我可以获得对这些对象的引用并在我的 for() 循环中实际设置它们?
  • 我会将它们都放在一个类中,声明并实例化这个类的实例,并将这个实例提供给两个构造函数。然后MyStruct 将持有对该实例的引用,您可以在循环中访问它。
  • 我真的不能声明“public ref Object objDest”,可以吗?
  • 不,您需要一个引用类型来保存数据值,然后更改该类型实例所拥有的值。
  • 对不起,我还没关注你。你能给出一个代码示例吗? (我还在上面添加了更多细节。)
【解决方案3】:

我仍然没有遵循您正在尝试做的事情......正如@JoelCoehoorn(和许多其他人)所说,您应该尝试使您的值类型(结构)不可变。这有点难看,但这是可行的。如果我对您想要做的事情有更好的理解,这可能会更清晰 - 我不提倡将此示例用于生产环境

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

【讨论】:

  • 对不起,您的代码也没有这样做。我在原始问题中添加了更多详细信息。 (而且,题外话,史蒂夫乔布斯会翻转说他的图像被用于 ASP.NET/C# 论坛......)
猜你喜欢
  • 2012-05-20
  • 1970-01-01
  • 2011-05-11
  • 2011-07-06
  • 1970-01-01
  • 2012-03-28
  • 2014-03-13
  • 1970-01-01
  • 2021-11-30
相关资源
最近更新 更多