0

If I'm serializing a collection of objects, what's the minimum type to guarantee that the collection is materialized (and not the result of an expression)?

e.g.. this should not be possible:

var message = new MyMessage {
  Recipients = someCollection.Select... // <- this can't be deserialized without calling ToList()
}

I know IList would do the job, but want to know if this is the minimum requirement.

Josh Kodroff
  • 27,301
  • 27
  • 95
  • 148
  • What Type is `someCollection`? Usually the minimum is `IEnumerable`. – Erik Philips Sep 08 '14 at 15:55
  • 1
    @ErikPhilips `IEnumerable` are allowed to lazy-load/execute, so its not that. – BradleyDotNET Sep 08 '14 at 15:57
  • Well *technically* that would be a return type, I should have just asked what the collection is. `AsEnumerable` will return a lazy loaded collection, and `ToList()` will return an explicitly loaded list, but it that would depend on EF vs Linq2Sql vs Linq2Entities. They aren't all quite the same. – Erik Philips Sep 08 '14 at 15:58

2 Answers2

7

I know IList would do the job

Actually, it would not. No interface can ever possibly have such a guarantee, because I can always make an implementation of that interface that defers materialization of any query until some of the interface methods are called. Now, by convention, a type implementing IList would be a materialized collection, and not something deferring work, but that is not a guarantee.

To have a guarantee you'll need to use a concrete type rather than an interface, accepting an array, List, etc.

Of course one option that you have is to accept an interface such as IEnumerable and then materialize it into a collection yourself (possibly as a 3rd overload with overloads for arrays and lists to avoid the need to re-materialize those) because if you've materialized it yourself then you know it's not deferring execution.

Servy
  • 202,030
  • 26
  • 332
  • 449
2

You can't. Whether a collection is materialized or a query is ultimately an implementation detail that is not exposed via any normal public API. However, if you want to be reasonably sure given common types, you can use ICollection<T>.

ICollection<T> requires that the Count be available. IList<T> further requires that you can access elements by index. Since you don't appear to need anything beyond IEnumerable<T>, I'd recommend ICollection<T>, e.g.

public ICollection<Recipient> Recipients { get; set; }

It may also be useful for you to create an IMaterialized or IMaterializedEnumerable<T> : IEnumerable<T> marker interface and class(es) that implement it, if ensuring that a collection is materialized is more important than being able to easily use built-in types and methods.

Community
  • 1
  • 1
Tim S.
  • 55,448
  • 7
  • 96
  • 122