如何在C#中返回一个字符串的引用?

4

我想要编写一个类似于以下的函数:

ref String TestIt( int index )
{
return this.TestArray[index];
};

这样我就可以写出像这样的代码:
MyClass.TestIt(0) = "Hello World";

我的目标是模仿这个C++声明

CString& MyClass::Data( UINT index);

我在这里所指的“引用”是指C++术语中变量的地址。
换句话说,在调用TestIT(0)后,TestArray[0]将包含“Hello World”。

编辑:我不能使用索引器,因为我的目标是将.cpp文件持续转换为C#。我能模拟这个C++代码,我就需要写更少的转换器。
7个回答

4
为了实现这个目标,您需要编写一个setter属性。不幸的是,在C#中,setter不能接受进一步的参数,因此您无法直接按照1:1的方式编写此代码。最接近的方法是使用一个带有默认属性的嵌套类:
class YourClass {
    public class Nested {
        public Nested(YourClass outer) { m_RefToOuterWorld = outer; }
        private readonly YourClass m_RefToOuterWorld;

        public string this[int index] {
            get { return m_RefToOuter.TestArray[index];
            set { m_RefToOuter.TestArray[index] = value; }
        }
    }

    private readonly Nested m_Nested;
    private string[] TestArray = new string[10];

    public YourClass() { m_Nested = new Nested(this); }

    public Nested TestIt { get { return m_Nested; } }
}

你可以像这样使用它:
var test = new YourClass();
test.TestIt[2] = "Hello world!";

顺便说一句,由于这需要很多努力,你可能不想这样做。而且,这种方式并不符合C#的风格。这里通过嵌套类的无用间接引用并不常见。


基于我的VB背景,我开始为他编写一个简单的索引属性,就像这样。然后我发现,虽然VB.Net支持此功能,但C#需要您创建一个全新的类。真遗憾。 - Joel Coehoorn
确实有点遗憾。不过说实话,我从来没有需要这个特定的VB功能。它主要用于模拟隐式CType运算符的语义,所以我们可以使用它来代替。 - Konrad Rudolph

2
简短回答是你不能返回一个字符串变量的引用,也就是一个字符串引用的引用。
简单的解决方案是避免这种API,并要求用户以另一种方式设置字符串。
myobj.SetString(0, "Hello, world!");

如果您真的需要将字符串引用表示为一级对象,请尝试使用以下 API:

Interface IStringReference
{
    void SetString(string value);
    string GetString();
}


class MyClass
{
    public IStringReference TestIt()
    {
        ... details left out ;) ...
    }
}

但我认为这样做在模仿C++的左值方面有些过头了。


1
我可以推荐以下解决方案。
 public class Test
    {
        Dictionary<int,string> str=new Dictionary<int,string>(); 
        public string this[int i]
        {
            get
            {
                return str[i];
            }
            set
            {
                if(!str.ContainsKey(i))
                    str.Add(i,value);
                else
                    str[i] = value;
            }
        }

0

你不需要返回一个引用来达到你的目标。字符串类型是引用类型,但对于比较有特殊处理。因此,如果你只是从TestIt返回一个字符串,等式检查将进行字符串比较。


它并不是在尝试进行字符串比较 - 它是在尝试进行赋值操作,因此无法正常工作。 - Jon Skeet

0
为什么要保持两个版本的代码相同呢?编写一个托管的 C++ 封装器,然后从 .Net 中使用它并调用适当的函数不是更容易吗?

我需要持续获取业务逻辑,我已经有了一个混合模式程序集,但是MFC有时候会出问题,因此我想使用100%托管代码来提高服务器的稳定性。 - Aaron Fischer

0
所有相同的字符串在代码中只有一个引用,无论它被引用多少次。
来自http://msdn.microsoft.com/en-us/library/system.string.intern.aspx 常见语言运行时通过维护一个称为内部池的表来节省字符串存储空间,该表包含程序中声明或以编程方式创建的每个唯一文字字符串的单个引用。因此,具有特定值的文字字符串实例在系统中只存在一次。
例如,如果将相同的文字字符串分配给多个变量,则运行时会从内部池中检索相同的文字字符串引用,并将其分配给每个变量。

1
这仅适用于字面字符串和您明确内部化的字符串!所有其他相同的字符串可能共享或不共享引用。 - Konrad Rudolph

0

你不是应该使用一个索引器(一个接受参数的匿名属性)吗?

private string []storage = new string[10];
public string this[int index]
{
  get
  {
    return storage[index];
  }
  set
  {
    storage[index] = value;
  }
}

然后调用:

MyClass[0] = "Hello World";

当然,它没有花哨的“TestIt”名称标签...你需要那个名称标签吗?

编辑:哈哈,我谷歌搜索了“C# 命名索引器”,我找到了谁在2005年回答愚蠢问题并给出了优秀答案?没错,是Jon Skeet


回复您的编辑:这并不奇怪,因为您可以在谷歌上搜索包含“C#”任何搜索词,并找到Jon的(优秀)答案。这家伙真是太无聊和可预测了。 - Konrad Rudolph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接