Horno
Horno

Reputation: 36

How to infer type from Collection C# Generics

I have this signature of an extension method from the System.IO.BinaryReader class.

public static T ReadCollection<T, R>(this BinaryReader reader, Func<BinaryReader, R> serializeItem) where T : ICollection<R>, new() {...}

Then I call that method like this

IList<User> users = new List<User>();
BinaryReader _reader = new BinaryReader(...);
...
...
 users = _reader.ReadCollection<List<User>, User>(reader => new User
 {
     Id = reader.ReadInt32(),
     Name = reader.ReadString()
 });

I wonder if it is possible to call it without specifing the type User twice. ReadCollection<List<User>, User>. Type arguments cannot be infered from the usage, so I must declare it explicity but Type R will always be the object from the Collection that is already defined. At the end I'm specifing in the generic type constraint where T: ICollection<R>

So the final call should be something like

_reader.ReadCollection<List<User>>(reader => new User...

instead of

_reader.ReadCollection<List<User>, User>(reader => new User...

Thanks in advance.

Upvotes: 0

Views: 206

Answers (2)

GraphWalk
GraphWalk

Reputation: 441

You dont need T at all:

public static ICollection<R> ReadCollection<R>(this BinaryReader reader, Func<BinaryReader, R> serializeItem) {...}

Or you can add items to any collection in deserializeItem delegate:

public static void ReadCollection(this BinaryReader reader, Action<BinaryReader> deserializeItem) {...}

var users = new List<User>();
_reader.ReadCollection(reader => users.Add(new User {
   Id = reader.ReadInt32(),
   Name = reader.ReadString()
});

Upvotes: 2

lidqy
lidqy

Reputation: 2463

If you drop the new() constraint (though it comes in handy generally) and pass in a factory, that just invokes 'new()' the type parameters can be interfered and omitted on invocation.

public static T ReadCollection<T, R>(this BinaryReader reader, Func<BinaryReader, R> serializeItem, Func<T> listFactory) where T : ICollection<R> {...}

In the body of the method new T() must be replace by listFactory().

Then you can call it like

var userList = reader.ReadCollection(reader => new User {..}, () => new List<User>());

or

var userList = reader.ReadCollection(reader => new User {..}, () => new HashSet<User>());

Upvotes: 1

Related Questions