Somewhat aside, that's not specifically a cast, its a conversion, and a conversion behaves slightly differently than a straight cast.
As
You can use the as operator to perform certain types of conversions between compatible reference types or nullable types...The as operator is like a cast operation. However, if the conversion isn't possible, as returns null instead of raising an exception.
I'm assuming that your Contact is a class created by CrmSvcUtil e.g. public partial class Contact : Microsoft.Xrm.Sdk.Entity, and service.Retrieve is IOrganizationService.Retrieve which has a return type of Entity.
Contact is a derived class of the base class Entity. You can't cast a base class to a more specific derived class (see Is it possible to assign a base class object to a derived class reference with an explicit typecast in C#?). If you tried to do a cast from Entity to Contact you would get an exception, and a conversion would return a null object.
Example with GeneratedCode from CrmSvcUtil included, but no actual connection to CRM.
var entity = new Entity();
Console.WriteLine($"Type of local entity: {entity.GetType()}");
Console.WriteLine($"Local entity as Contact is null? {entity as Contact == null}");
Output:
Type of local entity: Microsoft.Xrm.Sdk.Entity
Local entity as Contact is null? True
So given Retrieve returns an Entity, which can't be cast to Contact, how does your line of code (var contact = service.Retrieve("contact", id, new ColumnSet()) as Contact;) even work?
Well it's magic. Apparently if you include GeneratedCode from CrmSvcUtil within your application the Retrieve function returns the specific derived classes instead of the generic Entity.
Example with GeneratedCode from CrmSvcUtil included:
CrmServiceClient service = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Crm"].ConnectionString);
Contact c = new Contact()
{
LastName = "Test"
};
Guid contactId = service.Create(c);
var response = service.Retrieve("contact", contactId, new ColumnSet());
Console.WriteLine($"Type of response from CRM: {response.GetType()}");
Console.WriteLine($"Response from CRM as contact is null? {response as Contact == null}");
Outputs:
Type of response from CRM: Contact
Response from CRM as contact is null? False
Example with no generated code included:
CrmServiceClient service = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Crm"].ConnectionString);
Entity c = new Entity("contact");
c["lastname"] = "Test";
Guid contactId = service.Create(c);
var response = service.Retrieve("contact", contactId, new ColumnSet());
Console.WriteLine($"Type of response: {response.GetType()}");
Outputs:
Type of response: Microsoft.Xrm.Sdk.Entity
Back to your question. If you are including generated code in your project, given that Retrieve is returning a Contact anyway you are fine to just do a simple cast (e.g. (Contact)service.Retrieve(...)) or conversion (as). In terms of what what ToEntity does, it's not actually doing a cast or conversion. It creates a new object and performs a shallow copy among some other things. So use it if meets your need, but you can probably get away without it.
Decomplied code:
public T ToEntity<T>() where T : Entity
{
if (typeof(T) == typeof(Entity))
{
Entity entity = new Entity();
this.ShallowCopyTo(entity);
return entity as T;
}
if (string.IsNullOrWhiteSpace(this._logicalName))
{
throw new NotSupportedException("LogicalName must be set before calling ToEntity()");
}
string text = null;
object[] customAttributes = typeof(T).GetCustomAttributes(typeof(EntityLogicalNameAttribute), true);
if (customAttributes != null)
{
object[] array = customAttributes;
int num = 0;
if (num < array.Length)
{
EntityLogicalNameAttribute entityLogicalNameAttribute = (EntityLogicalNameAttribute)array[num];
text = entityLogicalNameAttribute.LogicalName;
}
}
if (string.IsNullOrWhiteSpace(text))
{
throw new NotSupportedException("Cannot convert to type that is does not have EntityLogicalNameAttribute");
}
if (this._logicalName != text)
{
throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Cannot convert entity {0} to {1}", new object[]
{
this._logicalName,
text
}));
}
T t = (T)((object)Activator.CreateInstance(typeof(T)));
this.ShallowCopyTo(t);
return t;
}