Note that there are some explanatory texts on larger screens.

plurals
  1. POCasting from interface to underlying type
    primarykey
    data
    text
    <p>Reviewing an <a href="https://stackoverflow.com/questions/4053636/c-permanent-casting-to-a-subclass">earlier question</a> on SO, I started thinking about the situation where a class exposes a value, such as a collection, as an interface implemented by the value's type. In the code example below, I am using a List, and exposing that list as IEnumerable. </p> <p>Exposing the list through the IEnumerable interface defines the intent that the list only be enumerated over, not modified. However, since the instance can be re-cast back to a list, the list itself can of course be modified.</p> <p>I also include in the sample a version of the method that prevents modification by copying the list item references to a new list each time the method is called, thereby preventing changes to the underlying list.</p> <p>So my question is, should all code exposing a concrete type as an implemented interface do so by means of a copy operation? Would there be value in a language construct that explicitly indicates "I want to expose this value through an interface, and calling code should only be able to use this value through the interface"? What techniques do others use to prevent unintended side-effects like these when exposing concrete values through their interfaces.</p> <p>Please note, I understand that the behavior illustrated is expected behavior. I am not claiming this behavior is wrong, just that it does allow use of functionality other than the expressed intent. Perhaps I am assigning too much significance to the interface - thinking of it as a functionality constraint. Thoughts?</p> <pre><code>using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace TypeCastTest { class Program { static void Main(string[] args) { // Demonstrate casting situation Automobile castAuto = new Automobile(); List&lt;string&gt; doorNamesCast = (List&lt;string&gt;)castAuto.GetDoorNamesUsingCast(); doorNamesCast.Add("Spare Tire"); // Would prefer this prints 4 names, // actually prints 5 because IEnumerable&lt;string&gt; // was cast back to List&lt;string&gt;, exposing the // Add method of the underlying List object // Since the list was cast to IEnumerable before being // returned, the expressed intent is that calling code // should only be able to enumerate over the collection, // not modify it. foreach (string doorName in castAuto.GetDoorNamesUsingCast()) { Console.WriteLine(doorName); } Console.WriteLine(); // -------------------------------------- // Demonstrate casting defense Automobile copyAuto = new Automobile(); List&lt;string&gt; doorNamesCopy = (List&lt;string&gt;)copyAuto.GetDoorNamesUsingCopy(); doorNamesCopy.Add("Spare Tire"); // This returns only 4 names, // because the IEnumerable&lt;string&gt; that is // returned is from a copied List&lt;string&gt;, so // calling the Add method of the List object does // not modify the underlying collection foreach (string doorName in copyAuto.GetDoorNamesUsingCopy()) { Console.WriteLine(doorName); } Console.ReadLine(); } } public class Automobile { private List&lt;string&gt; doors = new List&lt;string&gt;(); public Automobile() { doors.Add("Driver Front"); doors.Add("Passenger Front"); doors.Add("Driver Rear"); doors.Add("Passenger Rear"); } public IEnumerable&lt;string&gt; GetDoorNamesUsingCopy() { return new List&lt;string&gt;(doors).AsEnumerable&lt;string&gt;(); } public IEnumerable&lt;string&gt; GetDoorNamesUsingCast() { return doors.AsEnumerable&lt;string&gt;(); } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload