A document class with the following property cannot be retrieved from a collection (throws exception)...
IReadOnlyCollection<
{
get {...}
set{...}
}
The "set" code is never called when attempting to retrieve.
However, if I change the value type to ICollection<
The type IEnumerable is also a problem. However, I get a strange exception when I try to retrieve an object with FindById():
Result Message:
System.ArgumentException : The value "System.Object" is not of type "TRAL.Trapi.PriceQuant" and cannot be used in this generic collection.
Parameter name: value
Result StackTrace:
at System.ThrowHelper.ThrowWrongValueTypeArgumentException(Object value, Type targetType)
at System.Collections.Generic.List1.System.Collections.IList.Add(Object item)
at LiteDB.BsonMapper.DeserializeList(Type type, BsonArray value)
at LiteDB.BsonMapper.Deserialize(Type type, BsonValue value)
at LiteDB.BsonMapper.DeserializeObject(Type type, Object obj, BsonDocument value)
at LiteDB.BsonMapper.Deserialize(Type type, BsonValue value)
at LiteDB.BsonMapper.ToObject(Type type, BsonDocument doc)
at LiteDB.BsonMapper.ToObject[T](BsonDocument doc)
at LiteDB.LiteCollection1.
at System.Linq.Enumerable.SingleOrDefaultTSource
The "ThrowWrongValueTypeArgumentException" doesn't seem valid. Here is what my property looks like:
[code]
/// <summary>
/// Sorted list of "bid" price-quantities in descending order. A copy is made on assignment.
/// </summary>
public IEnumerable<PriceQuant> Bids
{
get { return _bids; }
set
{
DEBUG.Out("BIDS");
_bids = new SortedSet<PriceQuant>(value, _rev);
}
}
[/code]
The "PriceQuant" is a struct.
Simply switching to ICollection rather than IEnumerable or IReadOnlyCollection allows it to work.
Mapper doest not implement IReadOnlyCollection. Current version support only:
if (typeDef == typeof(IList<>) ||
typeDef == typeof(ICollection<>) ||
typeDef == typeof(IEnumerable<>))
{
return CreateInstance(GetGenericListOfType(UnderlyingTypeOf(type)));
}
Any of this will create instance as List<T> to use Add method to insert data.
https://github.com/mbdavid/LiteDB/blob/master/LiteDB/Mapper/Reflection/Reflection.cs#L137
Also, you can register your own type using RegisterType<T> from BsonMapper.Global instance.
OK, understand about IReadOnlyCollection. Howver, this does not work with IEnumerable:
private static RevComparer _rev = new RevComparer();
private ICollection<PriceQuant> _bids = new SortedSet<PriceQuant>(_rev);
public IEnumerable<PriceQuant> Bids
{
get { return _bids; }
set
{
_bids = new SortedSet<PriceQuant>(value, _rev);
}
}
However, simply switching to ICollection<<>> causes it to work.
PriceQuant is a simple struct with two double type properties.
Using a custom set in _bids = new SortedSet<PriceQuant>(value, _rev); still returing an IEnumerable and it's not possible use Add method.
When you change to IColleciton it's possible because ICollection contains Add.
Not sure understand.
You say that LiteCollection creates List
Any of this will create instance as List
to use Add method to insert data.
*List has the Add() method. *
Assigning a List object to my "Bids" property should work fine.
Yey, my last comment are wrong (i deleted). I marked this issue as "need review"... because it's need works.
I can add a little more information here.
I tested with a property of IEnumerable<double> and, bizarrely, it worked. IEnumerable<struct type> does not work however, whereas ICollection<struct type> does. This is strange!
I tested with the simpler code:
public struct TempStruct
{
public double _a;
public double _b;
public TempStruct(double p)
{
_a = p;
_b = 0;
}
public TempStruct(double p, double q)
{
_a = p;
_b = q;
}
}
...
Document:
private IList<TempStruct> _temp = new List<TempStruct>();
public int TempCount
{
get { return _temp.Count; }
}
public ICollection<TempStruct> TempList
{
get { return _temp; }
set { _temp = new List<TempStruct>(value); }
}
To test, I added 3 items and assigned to TempList.
This works fine. However, if we change to the following to:
public IEnumerable<TempStruct> TempList
It throws an exception when we deserialize.
System.ArgumentException : The value "System.Object" is not of type "TRAL.Trapi.TempStruct" and cannot be used in this generic collection.
Parameter name: value
This is strange indeed. Am i doing something wrong here?
PS. Making TempStruct a class and adding a default constructor does not work either. The result is the same.
Bingo! Method GetListItemType(Type listType) are not returning correct ItemType when listType are IEnumerable. Fixed.
Yeah! :)