显式和隐式的C#

83

我是C#的新手,正在学习新单词。当涉及到C#编程时,我很难理解这两个词的含义。

我在字典里查找了含义,以下是我得到的:

Implicit

“Implicit”意味着以间接的方式表达某事物。

“如果在某事物中内涵或元素是implicit,则它与该事物相关或被该事物所展现。”

Explicit

“Explicit”意味着明确和公开地表达或展示某事物,没有任何隐藏的尝试。

“如果您对某事物非常明确,则会非常开放和清晰地谈论它。”

我想了解C#中这两个词的含义。

谢谢你的帮助。

祝福你


附加信息:

这是我现在阅读的书中一句话的一部分,其中有这个单词"implicit"

“这意味着Area和Occupants在AreaPerPerson( )隐式地引用了调用AreaPerPerson( )的对象中发现的那些变量的副本。”

我不太理解这句话的含义。


也许我只是从未遇到过它们。但你指的是什么上下文呢?我以前从未听说过在C#中应用显式和隐式。 - Jimmy Chandra
事实上,在C#中有许多上下文可以给出答案范围。 - Colin Mackay
你引用的文本中使用的“implicit”对我和你来说一样神秘。它在那个上下文中可能有意义,但它肯定不是一般C#编程术语。 - reinierpost
9个回答

150

implicitexplicit关键字在 C# 中用于声明转换运算符。假设您有以下类:

public class Role
{
    public string Name { get; set; }
}

如果你想创建一个新的角色(Role)并为其指定一个名称(Name),通常会像这样做:

Role role = new Role();
role.Name = "RoleName";

由于它只有一个属性,如果我们可以像这样做,可能会更方便:

Role role = "RoleName";

这意味着我们想要 隐式地 将一个字符串转换为 Role(因为代码中没有特定的强制类型转换)。为了实现这一目的,我们添加一个隐式转换运算符:

public static implicit operator Role(string roleName)
{
    return new Role() { Name = roleName };
}

另一种选择是实现一个显式转换运算符:

public static explicit operator Role(string roleName)
{
    return new Role() { Name = roleName };
}
在这种情况下,我们不能将字符串隐式转换为Role,但是我们需要在代码中进行强制转换:
Role r = (Role)"RoleName";

10
很少!自定义转换和用户定义操作符一样,只有极少数情况下才有用。 - Jon Skeet
Jon是正确的。我不认为我曾经在生产代码中使用过这个。 - Fredrik Mörk
2
非常感谢!有时候我很难理解技术术语。这个讲解得非常好。再次感谢。 - tintincutes

73

一般来说

  • 隐式:某些操作会自动为您完成。
  • 显式:您在源代码中编写了一些内容以指示您想要发生什么。

例如:

int x = 10;
long y = x; // Implicit conversion from int to long
int z = (int) y; // Explicit conversion from long to int

隐式(Implicit)和显式(Explicit)在不同的上下文中都经常被使用,但它们的一般意思总是沿用这些基本含义。

需要注意的是,有时候这两者可以同时出现。例如:

int x = 10;
long y = (long) x; // Explicit use of implicit conversion!

显式转换指必须明确声明的转换;隐式版本则是可以隐式使用的,即代码不必声明。(An explicit conversion is one which has to be stated explicitly; an implicit version is one which can be used implicitly, i.e. without the code having to state it.)


在这里,var的别名不是隐式和显式类型很好的上下文吗? 隐式 var impl = new { Field1 = "EUR", Field2 = 9.40 }; 和显式的类定义 public class Conversion { string Field1 { get; set; } public double Field2 { get; set; } } 并分配 Conversion expl = new Conversion(); expl.Field1 = "EUR"; expl.Field2 = 9.40; - Independent
好的,我再试一次。在C#中,var被认为是“隐式类型变量”吗? - Independent
1
@Jonas:是的。你之前的评论包括匿名类型,但这与隐式类型有些不同。请注意,还有对象初始化器,因此您可以使用var conversion = new Conversion { Field1 = "EUR", Field = 9.40 }; - Jon Skeet
@Skeet 谢谢,你可能是对的,匿名类型在哪里被隐式声明?“隐式/显式”术语的另一个上下文。 对我来说,你的示例相当于 var st = new StreamReader(),其中有一个更智能的对象。但即使在那里,为了可读性,我们也会使用 Stream st = new Stream():). - Independent
@Skeet 对于打字错误我很抱歉。显然,该注释应该以1个对象作为样本。我们可以在这里结束,问题是匿名类型和强类型如何涉及隐式/显式。 - Independent
显示剩余2条评论

10

假设你有两个类:

internal class Explicit
{
    public static explicit operator int (Explicit a)
    {
        return 5;
    }
}


internal class Implicit
{
    public static implicit operator int(Implicit a)
    {
        return 5;
    }
}

还有两个对象:

var obj1 = new Explicit();
var obj2 = new Implicit();

现在您可以编写:

int integer = obj2; // implicit conversion - you don't have to use (int)

或者:

int integer = (int)obj1; // explicit conversion

但是:

int integer = obj1; // WON'T WORK - explicit cast required

隐式转换是指在转换时不会丢失任何精度。显式转换意味着您可能会失去一些精度,并且必须清楚地说明您知道自己在做什么。

还有第二个上下文,即应用隐式/显式术语的接口实现。在这种情况下没有关键字。

internal interface ITest
{
    void Foo();
}

class Implicit : ITest
{
    public void Foo()
    {
        throw new NotImplementedException();
    }
}

class Explicit : ITest
{
    void ITest.Foo() // note there's no public keyword!
    {
        throw new NotImplementedException();
    }
}

Implicit imp = new Implicit();
imp.Foo();
Explicit exp = new Explicit();
// exp.Foo(); // won't work - Foo is not visible
ITest interf = exp;
interf.Foo(); // will work

当您使用显式接口实现时,当您使用具体类型时,接口的方法不可见。这可以用于帮助接口而不是类主要职责的情况,并且您不希望其他方法误导使用您的代码的人。


2

我认为这个链接很清楚地解释了什么是隐式转换——它是一种无需在赋值时显式转换值的方式。因此,不需要执行以下操作:

myDigit = (Digit) myDouble 

你只需要这样做:

myDigit = myDouble;

1

C# 中的显式主要是指清晰明确地表达您的意图。

例如:

class MyClass
{
    string myField;

    void MyMethod(int someNumber)
    {

    }
}

在上述代码中,类、字段和方法的可见性都是隐含的。它们使用编译器默认设置。
现在,我总是记不住编译器的默认设置,或许你的同事也是如此。因此,为了避免大家记不住默认设置,最好显示地标明。
public class MyClass
{
    private string myField;

    public void MyMethod(int someNumber)
    {
    }
}

0

Implicit可以理解为暗示,但是explicit意味着你必须明确声明它必须由自己完成。就像强制转换一样。这里有一个隐式转换:

int implicit;
implicit = 7.5;

值 '7.5' 将隐式转换为 int。这意味着编译器会为您执行此操作。

这里是显式的:

int explicit;
explicit = (int)7.5;

在这里,您告诉编译器您想要进行强制转换。您明确声明了转换。希望这有所帮助。来源:http://cboard.cprogramming.com/cplusplus-programming/24371-implicit-explicit.html


0

微软代码生成器使用关键字“var”进行隐式声明,但我认为需要注意的是

var builder = WebApplication.CreateBuilder(args);

并且

WebApplicationBuilder? builder = WebApplication.CreateBuilder(args); 

是相同的,但是

var builder = WebApplication.CreateBuilder(args);

并且

WebApplicationBuilder builder = WebApplication.CreateBuilder(args); 

不是一样的。

为了代码清晰,我总是更喜欢显式地编写,但正如您所见,微软的代码生成器并非如此。从代码执行的角度来看,没有性能差异。


0
让我们以将“潜在客户”转换为“商机”的示例来理解这个问题。如果我们将“潜在客户”定义为
public class Lead
{
    public Guid Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

我们想将其转换为“Opportunity”。
public class Opportunity
{
    public string Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public decimal Worth {get;set;} 
}   

映射与转换

为了实现这一点,我们需要创建一个新的Opportunity实例,然后复制其值,因此我们创建了一个新的函数来完成这个任务,并且这个函数需要在一个class中。

public Opportunity Convert(Lead lead)
{
    Opportunity opp = new Opportunity();
    opp.Id = lead.Id.ToString();
    opp.FirstName = lead.FirstName;
    opp.LastName = lead.LastName;
    return opp;
}

所以我们将该方法移动到Opportunity类内部,并将其设为static,以便可以通过Opportunity.Convert()进行调用。
public class Opportunity
{
    public string Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public decimal Worth {get;set;} 
    
    public static Opportunity Convert(Lead lead)
    {
        Opportunity opp = new Opportunity();
        opp.Id = lead.Id.ToString();
        opp.FirstName = lead.FirstName;
        opp.LastName = lead.LastName;
        return opp;
    }
}

//main
void Main()
{
    Lead lead = new Lead();
    lead.Id = Guid.NewGuid();
    lead.FirstName = "Vinod";
    lead.LastName = "Srivastv";
    lead.Dump();
    

    Opportunity opp = Opportunity.Convert(lead);
    opp.Dump();
}

但是通过 explicitimplicit 我们可以声明转换操作符,这样就不需要调用 Opportunity 类的 Convert 方法。

implicit 示例

implicit 转换中,我们不需要手动进行对象强制转换,因为它会隐式地进行转换。

public class Opportunity
{
    public string Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public decimal Worth {get;set;} 
    
    public static implicit operator Opportunity(Lead lead)
    {
        Opportunity opp = new Opportunity();
        opp.Id = lead.Id.ToString();
        opp.FirstName = lead.FirstName;
        opp.LastName = lead.LastName;
        return opp;
    }
}

//main
void Main()
{
    Lead lead = new Lead();
    lead.Id = Guid.NewGuid();
    lead.FirstName = "Vinod";
    lead.LastName = "Srivastv";
    lead.Dump();
    
    // here the lead is implicitly converted to opportunity 
    //and we get rid of the Convert Method from above 
    Opportunity opp = lead;
    opp.Dump();
}

enter image description here

明确示例

现在我们刚刚从上面的代码中将关键词从隐式更改为明确:

public class Opportunity
{
    public string Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public decimal Worth {get;set;} 
    
    public static explicit operator Opportunity(Lead lead)
    {
        Opportunity opp = new Opportunity();
        opp.Id = lead.Id.ToString();
        opp.FirstName = lead.FirstName;
        opp.LastName = lead.LastName;
        return opp;
    }
}

//main
void Main()
{
    Lead lead = new Lead();
    lead.Id = Guid.NewGuid();
    lead.FirstName = "Vinod";
    lead.LastName = "Srivastv";
    lead.Dump();
    
    //CS0266 Cannot implicitly convert type '.Lead' to 'Opportunity'. 
    //An explicit conversion exists (are you missing a cast?)
    //Opportunity opp = lead;
    
    //This is an example of explicit conversion, see the casting
    Opportunity opp = (Opportunity)lead;
    opp.Dump();
}

当我们更改关键字时,编译器会抛出错误,错误信息为“存在显式转换(是否缺少强制转换?)”,因此我们需要将Lead对象转换为Opportunity对象,如上所示,使用(Opportunity)进行强制转换。

enter image description here


0

因为C#在编译时是静态类型的。

隐式转换:不需要特殊语法,因为转换总是成功的,也不会丢失数据。例如,从较小的整数类型转换为较大的整数类型,以及从派生类转换为基类。

显式转换(强制转换):显式转换需要一个强制转换表达式。当转换可能会丢失信息或者转换可能因其他原因而失败时,就需要进行强制转换。典型的例子包括将数字转换为精度或范围较小的类型,以及将基类实例转换为派生类。

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }

    public static explicit operator Person(Employe employe) => new Person { Id = employe.Id, Name = employe.Name };
}

public class Employe
{

    public int Id { get; set; }
    public string Name { get; set; }
    public string Family { get; set; }

    public static implicit operator Employe(Person person) => new Employe { Id = person.Id, Name = person.Name };
}

static void Main(string[] args)
{
    Person person = new Person() { Id = 1, Name = "Reza" };

    //implicit operator
    Employe employe = person;
    employe.Family = "Jenabi";

    //explicit operator
    Person person1 = (Person)employe;
}

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