C# 菜鸟值类型,引用类型的有关问题,求大家帮助一下

C# 初学者值类型,引用类型的问题,求大家帮助一下
private void Form1_Load(object sender, EventArgs e)
        {
            List<string> li = new List<string>();
            li.Add("方法");
            li.Add("小明");
            li.Remove("小明");

            List<xx> li2 = new List<xx>();
            xx xx = new xx() { A ="1" };
            xx xx1 = new xx() { A = "3"};
            li2.Add(xx);
            li2.Add(xx1);

            xx xx3 = new xx() { A = "1"};
            li2.Remove(xx3);
        }

        public class xx
        {
            public string A;
        }

代码如上图第一个 li.Remove("小明");可以删除掉
 li2.Remove(xx3); 删除不掉

List<String> li2 = new List<String>();

            String ss =  new String(new char[]{'A'});
            String ss1 = new String(new char[] { 'B' });
            li2.Add(ss);
            li2.Add(ss1);
            String ss33 = new String(new char[] { 'A' });
            li2.Remove(ss33);


同样li2.Remove(ss33);也可以删除掉

网上查到 string和自定义类都是引用类型,为什么在list泛型中效果不一样,新手求解答谢谢

------解决方案--------------------
话说你 xx xx = new xx() { A ="1" };
            xx xx1 = new xx() { A = "3"};
            li2.Add(xx);
            li2.Add(xx1);
 
            xx xx3 = new xx() { A = "1"};
你都没加到li2你怎么知道有没有删除,真是奇葩了,这个应该是可以删除的,都是泛型,都是xx类
------解决方案--------------------
字符串是引用类型,但真的很特别的一个。当你做两个字符串值,如
C = A ,这里的操作跟两个类的赋值不一样。所以C没有A的引用.而是创建一个新的字符串类,​​字符串A的值被复制到字符串C.字符串C和A指向完全地不同的内存地址。这样情况,当你有很多字符串操作,例如循环,并在每次迭代中,你有一个字符串操作,因为不断会生成新的String,该操作是性能泄漏。在这种情况下,应该使用StringBuilder 。为什么呢,因为StringBuilder的任何字符串操作不会创建新的字符串。

那么,为什么字符串不是值类型而是引用类型。
先说说int值, int类型定义的长度,那就是4个字节。而对于每一个值类型,你知道确切的内存空间。但对于字符串,你不知道。如果每次使用,你都定义足够的长,那么这是很浪费性能和空间的。
为什么string类特殊?因为他是一个引用类,但使用的方式,看起来像一个值类型。所以,这就是为什么你做的操作,如:
string C = A而不是string C =new string(A);
你不用初始化string类,当你第一次设置时,.Net框架已经为你做了这件事。如果没有设置值,像其他引用类型一样,它的值是null。
每一个语言平台的字符串类型都是进行特殊处理,.Net也不例外