C# 字符串、Int32等类和赋值的行为

C# 字符串、Int32等类和赋值的行为,c#,C#,这听起来可能很愚蠢。我们知道可以按如下方式为字符串变量赋值。 String name=“myname” 字符串是引用类型,但在声明和赋值时不需要new运算符。如果我想设计一个具有这种行为的自定义类,我将如何继续 谢谢内置的“编译器魔法”解决了这个问题。在后台,字符串、整数、long等的文字将转换为操作,以便在运行时正确创建相应的对象或值,而无需使用运算符new String和Int32都是类 从技术上讲,Int32是一个struct,而不是类,但同样的逻辑也适用。您不能用这种行为设计类。但是您可

这听起来可能很愚蠢。我们知道可以按如下方式为字符串变量赋值。
String name=“myname”

字符串是引用类型,但在声明和赋值时不需要
new
运算符。如果我想设计一个具有这种行为的自定义类,我将如何继续

谢谢

内置的“编译器魔法”解决了这个问题。在后台,字符串、整数、long等的文字将转换为操作,以便在运行时正确创建相应的对象或值,而无需使用运算符
new

String
Int32
都是类


从技术上讲,
Int32
是一个
struct
,而不是
,但同样的逻辑也适用。

您不能用这种行为设计
类。但是您可以设计一个
结构。而且您不需要做任何特殊的事情:只要声明一个
struct
,它就可以被实例化


至于
string s=“literal”
,string是一个类,但它使用literal的实例化是由编译器专门处理的。它相当于
string s=newstring(literal)

您要寻找的是一个隐式类型转换方法()。例如,假设您有一个名为“PositiveFloat”的类,该类自动将浮点钳制为大于等于0的值,那么您可以拥有以下类布局:

class PositiveFloat
{
    public float val = 0.0f;

    public PositiveFloat(float f)
    {
        val = Math.Max(f, 0.0f); //Make sure f is positive
    }

    //Implicitly convert float to PositiveFloat
    public static implicit operator PositiveFloat(float f)
    {
        return new PositiveFloat(f);
    }

    //Implicitly convert PositiveFloat back to a normal float
    public static implicit operator float(PositiveFloat pf)
    {
        return pf.val;
    }
}

//Usage
PositiveFloat posF = 5.0f; //posF.val == 5.0f
float fl = posF; //Converts posF back to float. fl == 5.0f
posF = -15.0f; //posF.val == 0.0f - Clamped by the constructor
fl = posF; //fl == 0.0f
对于本例,您可能还希望为
+
-
等提供隐式运算符方法,以支持此类上的浮点运算和整数运算

运算符不仅限于int这样的核心数据类型,您还可以通过使用“=”隐式地从一个类转换为另一个类,但这就需要开始判断上下文。做
事t=y有意义,或者应该是
事物t=新事物(y)甚至
东西t=y.ConvertToThing()?这取决于你


在C#的核心,int、float、char等基本数据类型是在编译器级别实现的,这样我们就有了一些基础。字符串,即使它看起来像引用类型。这些类型如何与运算符之类的东西一起工作,这实际上与上面的隐式运算符完全相同,但为了确保一致性,同时允许您完全在C#中创建自己的“基本”类型。

您可以使用隐式转换运算符通过自己的类实现这一点-基本上,在类中定义一个静态方法,该方法可以从值创建实例。选中此项:

public class MyClass
{
   public static implicit operator MyClass (int val)
   {
       return new MyClass { Value = new String('!', val)};
   }
   public string Value {get;set;}
}
这个类包含一个字符串。当从
int
隐式强制转换时,它将使用感叹号的数量
int
初始化类:

MyClass obj = 5;
Console.WriteLine(obj.Value); // outputs !!!!!
此功能称为文字常量。编译器仅对某些类型支持这些类型,其中大多数是我们非正式地称之为primitve类型的类型。这些是:

  • 布尔文本:
    true
    false

  • 整数文本:
    int
    uint
    long
    ulong

    文字的确切类型是通过文字的后缀指定的类型或从文字的值推断的类型(推断的类型将始终是有符号类型)

    如果推断类型不是变量的声明类型,则会自动执行隐式转换(如果可用)(否则会引发编译时错误)

  • 实数字面值:
    float
    double
    decimal

    除非文字的后缀另有规定,否则文字的类型将始终为
    double
    。同样,如果必要且可用,将执行对声明类型的变量的隐式转换

  • 字符文字:“a”、“1”、“u1000”等

  • 字符串文本:支持两种类型的文本字符串:常规字符串文本和逐字字符串文本:
    “C:\\Path”
    @“C:\Path”

  • 空文本:
    null

  • 所有这些都有编译器的特定支持。你无论如何都不能用这种行为来实现你自己的类型。您可以做的是实现从上述一个文本(null文本除外)到您的类型的隐式转换,并以某种方式模拟文本常量

    请记住,您仅使用视觉糖进行模仿,因为它们绝对不是文字常量:

    struct MyLiteralType
    {
         public static implicit MyLiteralType(int i) => new MyLiteralType(i);
    }
    
    const MyLiteralType myLiteralTypeConstant = 1; //--> compile time error.
    

    请查看struct vs class-但这些是基本类型而不是真正的类..String是一个特例:@user230910 String是引用类型rt?它是如何做到的?@AnuViswan string是一个特例。基本上,它是一个不可变的字符数组(不完全如此,使用指针等更糟糕),因此它是一个引用类型,而不是值类型。但是,它同时实现了
    ==
    =带有值检查的运算符,如中所示。这就是为什么它感觉有点像一个值类型。哇,这很酷,我想可能可以从“对象”或匿名类型执行此操作,因此您可以创建一个Myperson person=new{“name”:“joe”};不,这是错误的@Goodnight nerdpride
    int i=1
    不进行隐式类型转换。这只是一个在编译器中实现的赋值。不,它没有错@PatrickHofman。再次检查问题。OP不是问编译器的实现细节,而是问如何实现同样的行为不应为
    15
    ,而应为
    0
    ;-)我会将此标记为anwer。正如@GoodNightNerdPride正确地提到的,我并没有在编译器中寻找实现细节,而是寻找如何复制相同的行为。谢谢