C# 为什么通过引用传递数据集而不显式传递或引用参数?

C# 为什么通过引用传递数据集而不显式传递或引用参数?,c#,C#,我无法理解这段代码,这里的DataSet对象和string变量实现相同,但输出不同。我可以看到string变量输出背后的逻辑,但对于DataSet,我无法理解为什么 class Program { static void Main(string[] args) { DataSet ds = new DataSet(); FillDS(ds); PrintDS(ds);

我无法理解这段代码,这里的DataSet对象和string变量实现相同,但输出不同。我可以看到string变量输出背后的逻辑,但对于DataSet,我无法理解为什么

class Program
    {

        static void Main(string[] args)
        {
            DataSet ds = new DataSet();
            FillDS(ds);
            PrintDS(ds);
            string name = "old";
            AssignString(name);
            PrintString(name);
        }
        private static void AssignString(string name)
        {
            name = "new name";
        }
        private static void PrintString(string name)
        {
            Console.WriteLine(name);
        }
        private static void FillDS(DataSet ds)
        {
            ds.Tables.Add(new DataTable("tbl1"));
            ds.Tables.Add(new DataTable("tbl2"));
        }
        private static void PrintDS(DataSet ds)
        {
            foreach (DataTable item in ds.Tables)
            {
                Console.WriteLine(item.TableName);
            }
        }
    }
//Output:
//tbl1
//tbl2
//old

因为
数据集
字符串
都是引用类型,而在引用类型中,它始终是对象在托管堆上所在位置传递的内存地址。

字符串是不可变的,而且您没有修改字符串参数(不是您可以修改的),但是,您将为参数指定一个新的引用。原作仍在原处

使用
DataSet
,您正在修改它的内容,因为它是一种可变的引用类型,所以您可以在调用者中看到更改

Main

    DataSet ds = new DataSet();
    ds.Tables.Add(new DataTable("tbl3"));
    FillDS(ds);
然后在
FillDS
中为您的
数据集指定一个新引用,如:

private static void FillDS(DataSet ds)
{
    ds = new DataSet(); //Here 
    ds.Tables.Add(new DataTable("tbl1"));
    ds.Tables.Add(new DataTable("tbl2"));
}

您将看到,您的
数据集
仍然保留旧值,并且在调用
FillDS
后,不会修改任何内容
字符串
数据集
都是引用类型。因此,在这两种情况下,您都会传递引用

AssignString
方法中,您不会更改传递的
string
实例,而是将一个新实例(
“new name”
)分配给变量
name
name
变量实际上是一个参数这一事实并不重要(尽管重新分配参数被认为是一种不好的做法)


FillDS
中,您不会重新分配新实例,而是通过
ds访问和操作传递的实例的属性。表..

字符串也是引用类型。感谢@Habib的指点,我错过了“相同实现”这个比特,你是什么意思?在
AssignString
中,您正在为
name
参数指定一个新值。在
FillDS
中,您没有为
ds
参数分配任何内容。您正在对其调用更改其内容的方法。你能看出这两个动作是不一样的吗?如果在
FillDS
中指定了
ds=new DataSet()
,您会发现作为参数传入的数据集不会发生更改。我可能不会为传递给AssignString的参数指定新值,我可能会这样做:name.Remove(0,1);输出:old它们都是引用类型,为什么字符串不从原始数据中获取副本,而是从数据集获取副本?顺便说一句,如果我用intRead替换字符串,结果仍然相同。它不改变字符串,只返回一个新字符串。碰巧字符串没有改变它的方法;它们只返回不同的新字符串。请在
Main
函数中尝试此代码:
var s=“test”;s、 移除(0,1);控制台。写入线(s)。您将发现
String.Remove()
从不更改字符串。然后试试这个:
var s2=s.Remove(0,1);控制台写入线(s2)
您会发现
String.Remove()
返回的字符串与原始字符串不同。但是它不会更改原始属性。
string
类型中是否有与本例中的
DataSet
相同的属性?@MohamedAhmed No.
string
被设计为不可变的。对
字符串
实例的每一个可能操作都会返回一个值已更改的新实例,但不会更改当前实例。C#中是否有可变和不可变类型的主题/主题?我想我以前没有接触过这个话题,因为我发现
int
type的行为与
string
在这个例子中,如何判断一个类型是可变的还是不可变的?@MohamedAhmed这是一个开始,正如我所说,谷歌是你的朋友……我从第二个搜索结果开始:我如何判断一个类型是可变的还是不可变的?我发现
int
也是不可变的!文件。。。看到Eric Lippert的作品了吗