Creating generic Isolator<T> class for collection modidy inside foreach loop

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Andrus

    #1

    Creating generic Isolator<T> class for collection modidy inside foreach loop

    Code below causes error in class definition line

    .....Isolator<T >' does not implement interface member
    'System.Collect ions.IEnumerabl e.GetEnumerator ()'.
    'Myapp.Isolator <T>.GetEnumerat or()' cannot implement
    'System.Collect ions.IEnumerabl e.GetEnumerator ()' because it does not have
    the matching return type of 'System.Collect ions.IEnumerato r'.

    I tried to change method signature to

    public IEnumerator GetEnumerator()

    bu this causes another error

    ....Isolator<T> ' does not implement interface member
    'System.Collect ions.Generic.IE numerable<T>.Ge tEnumerator()'.
    'Myapp.Isolator <T>.GetEnumerat or()' cannot implement
    'System.Collect ions.Generic.IE numerable<T>.Ge tEnumerator()' because it does
    not have the matching return type of
    'System.Collect ions.Generic.IE numerator<T>'.

    How to make this code work ?

    Andrus.

    using System;
    using System.Collecti ons;
    using System.Collecti ons.Generic ;

    public class Isolator<T: IEnumerable<T>
    {
    IEnumerable<Tin ner;

    public Isolator(IEnume rable<Tenumerab le)
    {
    inner = enumerable;
    }

    public IEnumerator<TGe tEnumerator()
    {
    ArrayList<Tlist = new ArrayList<T>();
    foreach (object o in inner)
    list.Add(o);
    return list.GetEnumera tor();
    }
    }

  • Marc Gravell

    #2
    Re: Creating generic Isolator&lt;T&g t; class for collection modidy insideforeach loop

    Because IEnumerable<Tde rives from IEnumerable, you need to provide
    *both* forms of GetEnumerator() ; this is usually dona via explicit
    implementation. .. just add:

    IEnumerator IEnumerable.Get Enumerator()
    { // reuse typed enumerator
    return GetEnumerator() ;
    }

    Marc

    Comment

    • Andrus

      #3
      Re: Creating generic Isolator&lt;T&g t; class for collection modidy inside foreach loop

      Marc,

      Thank you. It works.
      I'm planning to use it to remove members in linq invoice rows like

      foreach (var row in new Isolator<TRow>( rowBindingSourc e))
      {
      if (row.Item == "VAT" || row.Item == "ROUNDING")
      rowBindingSourc e.Remove(row);
      }

      Where rowBindingSourc e type is your linq TableList class.

      Is this best style ?

      In VFP I can use SQL directly from my application code

      DELETE FROM rowBindingSourc e WHERE rows IN ("VAT", "ROUNDING")

      Why Linq to Objects requires to create loop manually, .i.e forces me to use
      procedural programming ?
      Why there is no delete command in linq or method like

      rowBindingSourc e.Remove( row=row.Item == "VAT" || row.Item ==
      "ROUNDING" );

      or

      from row in rowBindingSourc e
      where row=row.Item in ( "VAT", "ROUNDING" )
      delete row;

      Andrus.

      Comment

      • Jon Skeet [C# MVP]

        #4
        Re: Creating generic Isolator&lt;T&g t; class for collection modidy insideforeach loop

        On Jun 5, 10:39 am, "Andrus" <kobrule...@hot .eewrote:
        Code below causes error in class definition line
        <snip>

        Marc has provided the reason why this fails, and a fix - but if you're
        using C# 3 and .NET 3.5, you can just call ToList() on any
        IEnumerable<Tan d it'll have *nearly* the same effect - the main
        difference being the time of copying. If that's an issue, consider an
        extension method:

        public static IEnumerable<TCo pyLazily(this IEnumerable<Tso urce) {
        List<Tlist = source.ToList() ;
        foreach (T t in list)
        {
        yield return t;
        }
        }

        It makes life a lot simpler :)

        Jon

        Comment

        • Jon Skeet [C# MVP]

          #5
          Re: Creating generic Isolator&lt;T&g t; class for collection modidy insideforeach loop

          On Jun 5, 11:23 am, "Andrus" <kobrule...@hot .eewrote:
          Thank you. It works.
          I'm planning to use it to remove members in linq invoice rows like
          >
          foreach (var row in new Isolator<TRow>( rowBindingSourc e))
          {
          if (row.Item == "VAT" || row.Item == "ROUNDING")
          rowBindingSourc e.Remove(row);
          }
          >
          Where rowBindingSourc e type is your linq TableList class.
          >
          Is this best style ?
          Well, I'd just use:

          foreach (var row in rowBindingSourc e.ToList())
          {
          ...
          }

          Alternatively you could put a call to Where after .ToList() and remove
          every matching row in the loop.
          In VFP I can use SQL directly from my application code
          >
          DELETE FROM rowBindingSourc e WHERE rows IN ("VAT", "ROUNDING")
          >
          Why Linq to Objects requires to create loop manually, .i.e forces me to use
          procedural programming ?
          LINQ is designed to be side-effect free. Deleting is a side-effect.
          Moreover, LINQ to Objects is based on IEnumerable, which has no notion
          for deleting. What would you expect to happen if you tried to delete
          from an array, for example?

          Jon

          Comment

          • Anthony Jones

            #6
            Re: Creating generic Isolator&lt;T&g t; class for collection modidy inside foreach loop


            "Andrus" <kobruleht2@hot .eewrote in message
            news:euYezYvxIH A.1772@TK2MSFTN GP03.phx.gbl...
            Marc,
            >
            In VFP I can use SQL directly from my application code
            >
            DELETE FROM rowBindingSourc e WHERE rows IN ("VAT", "ROUNDING")
            >
            Why Linq to Objects requires to create loop manually, .i.e forces me to
            use
            procedural programming ?
            Why there is no delete command in linq or method like
            >
            rowBindingSourc e.Remove( row=row.Item == "VAT" || row.Item ==
            "ROUNDING" );
            >
            or
            >
            from row in rowBindingSourc e
            where row=row.Item in ( "VAT", "ROUNDING" )
            delete row;
            The Q in LINQ stands for Query.

            DELETE is not a query, it modifies the stored data.


            --
            Anthony Jones - MVP ASP/ASP.NET


            Comment

            • Marc Gravell

              #7
              Re: Creating generic Isolator&lt;T&g t; class for collection modidy insideforeach loop

              Well, even indirectly, mixing enumeration and editing (removal) of a
              list is not a greate idea.

              Re the difference between SQL delete and .NET version; well, LINQ is
              object orientated (SQL isn't); if you want to do anything in LINQ, you
              do it to the instances. This is no different. Apart from this, there are
              also issues like:
              * concurrency management - hard to do on a block delete
              * identity: if the data-context issues a block delete, how does it know
              which records the database actually deleted? to update it's own local
              cache of objects...
              * LINQ can be configured to to the CRUD through SPs; how would it issue
              a block-delete through a DELETE sproc that only accepts a PKID?

              If this is going to be doing a lot of work, then I would create an SP
              and call that (you can expose SPs with arguments etc to LINQ-to-SQL very
              easily).

              If you are dealing with smaller volumes, and you want a Remove(fn) on
              some local class, then just add one!

              Marc

              Comment

              • Andrus

                #8
                Re: Creating generic Isolator&lt;T&g t; class for collection modidy inside foreach loop

                Well, I'd just use:
                >
                foreach (var row in rowBindingSourc e.ToList())
                {
                ...
                }
                >
                Alternatively you could put a call to Where after .ToList() and remove
                every matching row in the loop.
                Thank you. Delete needs to scan over whole collection always.
                So I changed foreach to use ToArray()

                foreach (var row in rowBindingSourc e.ToArray() )
                {
                if (row.Item == "VAT" || row.Item == "ROUNDING")
                rowBindingSourc e.Remove(row);
                }

                hope this faster than ToList().

                Is it reasonable/how to create generic static method which implements this
                mass-Remove() for IList<Tcollecti ons ?
                Since covariant types are not supported in C#, generic type parameter should
                be used probably.

                Andrus.

                Comment

                • Jon Skeet [C# MVP]

                  #9
                  Re: Creating generic Isolator&lt;T&g t; class for collection modidy insideforeach loop

                  On Jun 5, 1:33 pm, "Andrus" <kobrule...@hot .eewrote:
                  Alternatively you could put a call to Where after .ToList() and remove
                  every matching row in the loop.
                  >
                  Thank you. Delete needs to scan over whole collection always.
                  Yes, but if you are only *acting* on certain elements, you can call
                  Where() to only get those items:

                  var toDelete = rowBindingSourc e.Where(row =row.Item=="VAT " ||
                  row.Item=="ROUN DING").ToList() ;
                  foreach (var row in toDelete)
                  {
                  rowBindingSourc e.Remove(row);
                  }
                  So I changed foreach to use ToArray()
                  <snip>
                  hope this faster than ToList().
                  I'd expect it to be slower in some cases, actually - because it needs
                  to accurately count the number of items before creating the array.
                  Is it reasonable/how to create generic static method which implements this
                  mass-Remove() for IList<Tcollecti ons ?
                  Yes, that would be easy to do as an extension method.
                  Since covariant types are not supported in C#, generic type parameter should be used probably.
                  Absolutely.

                  Just offhand (untested):

                  public static void RemoveWhere<T(t his IList<Tsource, Func<T,bool>
                  predicate)
                  {
                  List<TtoRemove = source.Where(pr edicate).ToList ();
                  foreach (T t in toRemove)
                  {
                  source.Remove(t );
                  }
                  }

                  Jon

                  Comment

                  Working...