Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interfaces, Inheritance, Implicit operators and type conversions, why is it this way?

Tags:

I'm working with a class library called DDay ICal. It is a C# wrapper for the iCalendar System implemented in Outlook Calendars, and many many many more systems. My question is derived from some work I was doing with this system.

There are 3 objects in question here

  • IRecurrencePattern - Interface
  • RecurrencePattern - Implementation of IRecurrencePattern Interface
  • DbRecurPatt - Custom Class that has an implicit type operator

IRecurrencePattern: Not all code is shown

public interface IRecurrencePattern {     string Data { get; set; } } 

RecurrencePattern: Not all code is shown

public class RecurrencePattern : IRecurrencePattern {     public string Data { get; set; } } 

DbRecurPatt: Not all code is shown

public class DbRecurPatt {     public string Name { get; set; }     public string Description { get; set; }      public static implicit operator RecurrencePattern(DbRecurPatt obj)     {         return new RecurrencePattern() { Data = $"{Name} - {Description}" };     } } 

The confusing part: Through out DDay.ICal system they are using ILists to contain a collection of Recurrence patterns for each event in the calendar, the custom class is used to fetch information from a database and then it is cast to the Recurrence Pattern through the implicit type conversion operator.

But in the code, I noticed it kept crashing when converting to the List<IRecurrencePattern> from a List<DbRecurPatt> I realized that I needed to convert to RecurrencePattern, then Convert to IRecurrencePattern (as there are other classes that implement IRecurrencePattern differently that are also included in the collection

var unsorted = new List<DbRecurPatt>{ new DbRecurPatt(), new DbRecurPatt() }; var sorted = unsorted.Select(t => (IRecurrencePattern)t); 

The above code does not work, it throws an error on IRecurrencePattern.

var sorted = unsorted.Select(t => (IRecurrencePattern)(RecurrencePattern)t); 

This does work tho, so the question I have is; Why does the first one not work? (And is there a way to improve this method?)

I believe it might be because the implicit operator is on the RecurrencePattern object and not the interface, is this correct? (I'm new to interfaces and implicit operators)

like image 449
Alec Scratch Avatar asked Aug 26 '15 12:08

Alec Scratch


People also ask

What do you mean by type conversion How is implicit?

Overview. Implicit type conversion in C language is the conversion of one data type into another datatype by the compiler during the execution of the program. It is also called automatic type conversion.

Why are implicit conversions possible in C?

Implicit type conversion in C happens automatically when a value is copied to its compatible data type. During conversion, strict rules for type conversion are applied. If the operands are of two different data types, then an operand having lower data type is automatically converted into a higher data type.

What are the types of conversion?

There are two types of conversion: implicit and explicit. The term for implicit type conversion is coercion. Explicit type conversion in some specific way is known as casting. Explicit type conversion can also be achieved with separately defined conversion routines such as an overloaded object constructor.

What is the need for conversion of data type in C sharp?

Type conversion happens when we assign the value of one data type to another. If the data types are compatible, then C# does Automatic Type Conversion. If not comparable, then they need to be converted explicitly which is known as Explicit Type conversion. For example, assigning an int value to a long variable.


1 Answers

You have basically asked the compiler to do this:

  1. I have this: DbRecurPatt
  2. I want this: IRecurrencePattern
  3. Please figure out a way to get from point 1. to point 2.

The compiler, even though it may only have one choice, does not allow you to do this. The cast operator specifically says that DbRecurPatt can be converted to a RecurrencePattern, not to a IRecurrencePattern.

The compiler only checks if one of the two types involved specifies a rule on how to convert from one to the other, it does not allow intermediary steps.

Since no operator has been defined that allows DbRecurPatt to be converted directly to IRecurrencePattern, the compiler will compile this as a hard cast, reinterpreting the reference as a reference through an interface, which will fail at runtime.

So, the next question would be this: How can I then do this? And the answer is you can't.

The compiler does not allow you to define a user-defined conversion operator to or from an interface. A different question here on Stack Overflow has more information.

If you try to define such an operator:

public static implicit operator IRecurrencePattern(DbRecurPatt obj) {     return new RecurrencePattern() { Data = $"{obj.Name} - {obj.Description}" }; } 

The compiler will say this:

CS0552
'DbRecurPatt.implicit operator IRecurrencePattern(DbRecurPatt)': user-defined conversions to or from an interface are not allowed

like image 103
Lasse V. Karlsen Avatar answered Oct 01 '22 09:10

Lasse V. Karlsen