如何在没有新的情况下调用构造函数

Sup*_*zar 3 c# constructor

我知道字符串就像一个类,当创建一个新字符串时,字符串本身并不欠值,而只是值的指针.但是在创建字符串时,不需要使用new;

string a = "hello";
Run Code Online (Sandbox Code Playgroud)

并不是

string a = new string("hello");
Run Code Online (Sandbox Code Playgroud)

我知道第二个选项也是可能的,但我想了解的是为什么第一个?

假设我有一个类名学生,他的构造函数得到了string.要创建一个新类,我必须使用保存的单词new.

student example = new student("Sabrina");
Run Code Online (Sandbox Code Playgroud)

我尝试过载,oparator =但这是不可能的.

如何创建一个像string(不使用单词new)的新类?

student example = "Sabrina"; 
Run Code Online (Sandbox Code Playgroud)

Ale*_*ria 10

您可以隐式使用强制转换运算符:

    sealed class Student
    {
        public string Name
        {
            get;
            private set;
        }

        Student()
        {
        }

        public static implicit operator Student(string name)
        {
            return new Student
            {
                Name = name
            };
        }
    }
Run Code Online (Sandbox Code Playgroud)

那你可以做Student student = "Sabrina";.

  • +1.请注意,`string`使用不同的机制 - 在编译器中实现的特殊情况(类似于`int` ...),用户无法扩展. (3认同)
  • 我同意@AlexeiLevenkov.虽然这看起来像"有效",但有很好的理由不这样做.例如,`Student a ="John Doe";`和`Student b ="John Doe";`将导致两个不同的对象与Object.Equals方法无法比较.你必须覆盖`Student`的equals方法,但这只会进一步混淆问题. (2认同)
  • 另外,当你做`Student student ="Sabrina"时真正发生的事情;``是`string`的实例是通过原始海报想知道的这个"魔法"创建的,然后是对`string`对象的引用传递给主体中的`implicit operator`方法,其中`Student`实例是用`new`关键字创建的!所以这是一种作弊行为.真正的答案是C#语法和公共语言运行时以非常特殊的方式处理类`string`.所以你不能编写自己的类,就像`string`一样. (2认同)

mor*_*ire 6

"hello"在所有情况下,代码中的字符串都不涉及对构造函数的调用.它是在编译时创建的常量值,这样字符串的所有实例"hello"都是相同的对象.类似地,整数1和十进制值3.456以及任何其他"文字"值是在运行时之前存在的常量,在构造函数代码有机会被调用之前.

代码new string("hello");无法调用,因为没有字符串构造函数将字符串作为值.但是,如果将其更改为new string("hello".ToCharArray());,则会得到一个字符串对象,但它与字符串不同"hello".实际上,您已经在一个单独的内存位置创建了一个新字符串"hello".它恰好恰好包含在其中的相同字符值"hello".

重要的是,如果你使用隐式类型转换技巧,那么转换为你的类型的一个字符串文字将不是同一个对象:

class Foo
{
    private string value;
    public Foo(string val)
    {
        this.value = val;
    }
    public static implicit operator Foo(string value)
    {
        return new Foo(value);
    }
}

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        Foo a = "asdf";
        Foo b = "asdf";
        Assert.AreNotEqual(a, b);
    }
}
Run Code Online (Sandbox Code Playgroud)

换句话说,a.Equals(b)返回false.为了使Equals方法返回true,您必须覆盖Foo类中的Equals方法.

public override bool Equals(object obj)
{
    return obj is Foo && value.Equals(((Foo)obj).value);
}
Run Code Online (Sandbox Code Playgroud)

但是,正如其他海报所提到的,这是一种混淆.您将难以使用代码以及难以调试它.它改变了对完整方法调用的常规赋值.它打破了Visual Studio为检查代码提供的许多工具,例如F12以跳转到方法定义.

隐式类型转换仅应在两种类型实际上在使用中完全可互换的情况下使用,其功能上存在细微差别.该float类型可隐式转换为double因为有没有多余的方法和功能doubleVS float,并从提高精度float,以double不改变价值.然而,从去double到float需要一个明确的演员阵容,因为精度损失变化所代表的价值.


eou*_*3hf 6

虽然你可以使用一个完成implicit operator,但我强烈建议你不要这样做.Strings在C#中特殊的动物,他们得到特殊待遇-与其他特殊类等一起int和float,你可以创建他们没有明确的new荷兰国际集团起来,由于C#编译器的工作方式:

var myInt = 0;
var myFloat = 0f;
var myString = "string";
Run Code Online (Sandbox Code Playgroud)

但是,此行为通常仅限于那些特殊类.implicit operator由于多种原因,添加执行此操作是不好的做法:

  • 它隐藏了下面实际发生的事情.new Student从转换到转换时我们是否在创建引擎盖string?
  • 这是不可维护的.当你必须在构造函数中添加另一个参数以包含StudentID号时会发生什么?
  • 它消除了使用隐式类型变量的可能性.你不能打电话var student = "name"; 你必须打电话Student student = "name".

该implicit operator模式非常迅速分解.虽然这是一件很酷的事情,但是你要在艰难的时刻为自己做好准备,让你的代码更难以阅读.我强烈建议只使用new Student("name")C#中的所有其他普通对象.