Static implicit operator
Asked Answered
G

5

215

I recently found this code:

 public static implicit operator XElement(XmlBase xmlBase)
 {
     return xmlBase.Xml;
 }

What does static implicit operator mean?

Goodson answered 25/11, 2010 at 4:32 Comment(0)
B
345

This is an implicit conversion operator. It means that you can write this code:

XmlBase myBase = new XmlBase();
XElement myElement = myBase;

And the compiler won't complain! At runtime, the conversion operator will be executed - passing myBase in as the argument, and returning a valid XElement as the result.

It's a way for you as a developer to tell the compiler:

even though these look like two totally unrelated types, there is actually a way to convert from one to the other; just let me handle the logic for how to do it.

Bemean answered 25/11, 2010 at 4:38 Comment(5)
+1. I would add that while there are occasional good usages of implicit conversion, it can also cause strange/surprising bugs, and can confuse a (human) API user. By way of example, there are very few usages of implicit conversions in the BCL. Use with discretion!Staging
I would highly appreciate if someone could give any real life scenarios where this is useful, and this came to rescue where other things could not be used or were inefficient. Thanks!Puddling
@Puddling I have an example in a project (admittedly over a decade old) - LINQ to SimpleDB, where we have a SimpleDbAttributeValue that could be a number, or a string, or some other value types, and we want to allow the customer to write simple code like myValue > 2 and the implicit conversion and operator overloading makes it natural. github.com/rexm/SimpleDb.NetBemean
A good example would be the Microsoft.Azure.Cosmos.DatabaseResponse class from the Microsoft.Azure.Cosmos.Client assembly. There it allows users receiving a DatabaseResponse to extract the requested Database object with a simple statement. The DatabaseResponse meanwhile contains information regarding the original api request made (f.x. whether CreateDatabaseIfNotExistsAsync return HTTP Status Code 201 or 200)Zoie
Well... I guess better late than never to find out about a language featureFatherless
A
16

Such an implicit operator means you can convert XmlBase to XElement implicitly.

XmlBase xmlBase = WhatEverGetTheXmlBase();
XElement xelement = xmlBase;   
//no explicit convert here like: XElement xelement = (XElement)xmlBase;
Anile answered 25/11, 2010 at 4:36 Comment(2)
can this explicit conversion work anyway ? XElement xelement = (XElement)xmlBase; In the question it says static, what does it have to be static? Can't it be non-static, so it can be instantiated?Winery
This is probably too late, but there is an answer to this question in this stackoverflow question. You should read the Eric Lippert's blog in the one of the answers too.Metencephalon
T
13

Another interesting usage is (which Unity did to check if an object (and therefore an instance of MonoBehavior) is null):

public static implicit operator bool (CustomClass c)
{
    return c != null;
}

Note that the code has to be inside the class (CustomClass in this case). That way you can do something like this:

void Method ()
{
    CustomClass c1 = null;
    CustomClass c2 = new CustomClass ();

    bool b1 = c1; // is false
    bool b2 = c2; // is true

    if (!c1 && c2)
    {
        // Do stuff
    }
}

Obviously the most notorious use might be using it to convert one of your classes to another of your classes. But using them with basic types is worth a consideration as well... and I see it mentioned quite rarely.

Thundering answered 10/7, 2018 at 14:42 Comment(3)
Nice trick! One thing to note: the static implicit operator bool method must be declared inside the CustomClass. I've created a DotNetFiddle for it for demo purpose.Spadiceous
@Spadiceous - Ah, my answer is 2 years old by now. I updated the code a little and added your hint.Thundering
Looks like somebody likes to write Javascript-like code in C#Justajustemilieu
C
4

It's an implicit conversion operator (as opposed to an Explicit operator, which requires the (type) conversion syntax)

Cloth answered 25/11, 2010 at 4:37 Comment(0)
R
3

My two cents.

This is useful in Unit testing an immutable entity to be used with Builder Pattern.

Say you have Employee domain object defined in an immutable way. We do this typically when want to adhere to DDD style.

public class Employee 
{ 
  public Employee(int id, string firstname, string lastname, DateTime birthdate, string street) 
  { 
    this.ID = id; 
    this.FirstName = firstname; 
    this.LastName = lastname; 
    this.BirthDate = birthdate; 
    this.Street = street; 
  } 

  public int ID { get; private set; } 
  public string FirstName { get; private set; } 
  public string LastName { get; private set; }
  public DateTime BirthDate { get; private set; } 
  public string Street { get; private set; } 

  public string getFullName() 
  { 
    return this.FirstName + " " + this.LastName; 
  } 

  public int getAge() 
  { 
    DateTime today = DateTime.Today;
    int age = today.Year - BirthDate.Year;
    
    if (BirthDate > today.AddYears(-age))
      age--;

    return age; 
  } 
}

Now you can have an employee builder like the following(inside of the test project). Notice in the end, we have this implicit operator.

public class EmployeeBuilder
{ 
  private int id = 1; 
  private string firstname = "first"; 
  private string lastname = "last"; 
  private DateTime birthdate = DateTime.Today; 
  private string street = "street"; 
  public Employee Build() 
  { 
    return new Employee(id, firstname, lastname, birthdate, street); 
  } 
  public EmployeeBuilder WithFirstName(string firstname) 
  { 
    this.firstname = firstname; 
    return this; 
  } 
  public EmployeeBuilder WithLastName(string lastname) 
  { 
    this.lastname = lastname; 
    return this; 
  } 
  public EmployeeBuilder WithBirthDate(DateTime birthdate) 
  { 
    this.birthdate = birthdate; 
    return this; 
  } 
  public EmployeeBuilder WithStreet(string street) 
  { 
    this.street = street; 
    return this; 
  } 
  public static implicit operator Employee(EmployeeBuilder instance) 
  { 
    return instance.Build(); 
  } 
}

Now you can have a employee test class like the following.

public class EmployeeTest
{
  [Test]
  public void GetFullNameReturnsCombination()
  { 
    // Arrange
    Employee emp = new EmployeeBuilder().WithFirstName("Vivek").WithLastName("Koppula"); 
    // Act
    string fullname = emp.getFullName(); 
    // Assert
    Assert.That(fullname, Is.EqualTo("Vivek Koppula")); 
  } 

  [Test] 
  public void GetAgeReturnsCorrectValue() { 
  // Arrange
  Employee emp = new EmployeeBuilder().WithBirthDate(new DateTime(1983, 1,1)); 
  // Act
  int age = emp.getAge(); 
  // Assert
  Assert.That(age, Is.EqualTo(DateTime.Today.Year - 1983)); 
  } 
}

This makes writing unit tests easier by enabling us to construct the employee just with required parameters.

For example in the first test, we are only concerned with first name and last name. So for the first case, we don't have to be bothered by age and street.

Similarly for the second case, we are concerned with age and nothing else.

Article References.

  1. flexible-and-expressive-unit-tests-with-the-builder-pattern
  2. improve-tests-with-the-builder-pattern-for-test-data
Rochdale answered 30/1, 2022 at 7:36 Comment(1)
Outside the question scope, but definetely valuable knowledge. +1Adamantine

© 2022 - 2024 — McMap. All rights reserved.