question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

NullReferenceException when trying to insert objects from a class that implements the IEnumerable<T> interface

See original GitHub issue

Hi!

Sorry for my bad english.

I’m using the version 4.0.0 downloaded from NuGet.

Below there is a example that works fine. A class containing a list of strings:

/// <summary>
/// Classe simples, contendo uma propriedade com listagem de strings
/// </summary>
class Example
{
	[BsonId(true)]
	public int Id { get; set; }

	public List<string> Elements { get; set; }

	public Example(string[] array)
	{
		this.Elements = new List<string>(array);
	}
}

/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(params string[] args)
{
	string[] ratings = new string[] { "AAA+", "AAA", "AAA-", "AAB", "BBB+", "BBB", "BBB-" };

	using (LiteDatabase db = new LiteDatabase(Path.Combine(Base.ApplicationData, "LiteDB.db")))
	{
		LiteCollection<Example> ratingsllection = db.GetCollection<Example>("ratings");

		ratingscollection.Insert(new Example(ratings));
	}
}

Now if I make my class implements the IEnumerable<string> interface I get a NullReferenceException when i try to insert a new object. Example below:

/// <summary>
/// Classe contendo listagem de strings e que implementada a interface de enumeração
/// </summary>
class EnumerableExample : IEnumerable<string>
{
	[BsonId(true)]
	public int Id { get; set; }

	public List<string> Elements { get; set; }

	public EnumerableExample(string[] array)
	{
		this.Elements = new List<string>(array);
	}

	IEnumerator<string> IEnumerable<string>.GetEnumerator()
	{
		return this.Elements.GetEnumerator();
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return this.Elements.GetEnumerator();
	}
}

/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(params string[] args)
{
	string[] ratings = new string[] { "AAA+", "AAA", "AAA-", "AAB", "BBB+", "BBB", "BBB-" };

	using (LiteDatabase db = new LiteDatabase(Path.Combine(Base.ApplicationData, "LiteDB.db")))
	{
		LiteCollection<EnumerableExample> ratingscollection = db.GetCollection<EnumerableExample>("ratings");

		ratingscollection.Insert(new EnumerableExample(ratings));
	}
}

Now, if I create a class that don’t extends the IEnumerable<string> but this class contais a property from another class that extends the same interface then my object is saved whitout problems:

/// <summary>
/// Classe contendo listagem de strings e que implementada a interface de enumeração
/// </summary>
class EnumerableExample : IEnumerable<string>
{
	public List<string> Elements { get; set; }

	public EnumerableExample(string[] array)
	{
		this.Elements = new List<string>(array);
	}

	IEnumerator<string> IEnumerable<string>.GetEnumerator()
	{
		return this.Elements.GetEnumerator();
	}

	IEnumerator IEnumerable.GetEnumerator()
	{
		return this.Elements.GetEnumerator();
	}
}

/// <summary>
/// Contem referência para a classe <see cref="EnumerableExample"/>
/// </summary>
class ContainsEnumerableExample
{
	[BsonId(true)]
	public int Id { get; set; }

	public EnumerableExample Elements { get; set; }

	public ContainsEnumerableExample(string[] array)
	{
		this.Elements = new EnumerableExample(array);
	}
}

/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(params string[] args)
{
	string[] ratings = new string[] { "AAA+", "AAA", "AAA-", "AAB", "BBB+", "BBB", "BBB-" };

	using (LiteDatabase db = new LiteDatabase(Path.Combine(Base.ApplicationData, "LiteDB.db")))
	{
		LiteCollection<ContainsEnumerableExample> ratingscollection = db.GetCollection<ContainsEnumerableExample>("ratings");

		ratingscollection.Insert(new ContainsEnumerableExample(ratings));
	}
}

As this error was puzzling me, I downloaded the code from GitHub and used it in my project directly. When I try to insert my IEnumberable object I get the following stack:

Date: 18/12/2017 09:42:38
Type: NullReferenceException
Message: Object reference not set to an instance of an object.
Data:	
Stack:	   at LiteDB.BsonMapper.ToDocument[T](T entity) in ..\LiteDB-4\LiteDB\Mapper\BsonMapper.Serialize.cs:line 29
	   at LiteDB.LiteCollection`1.<GetBsonDocs>d__35.MoveNext() in ..\LiteDB-4\LiteDB\Database\Collections\Insert.cs:line 65
	   at LiteDB.LiteEngine.<>c__DisplayClass20_0.<Insert>b__0(CollectionPage col) in ..\LiteDB-4\LiteDB\Engine\Engine\Insert.cs:line 33
	   at LiteDB.LiteEngine.Transaction[T](String collection, Boolean addIfNotExists, Func`2 action) in ..\LiteDB-4\LiteDB\Engine\LiteEngine.cs:line 211
	   at LiteDB.LiteEngine.Insert(String collection, IEnumerable`1 docs, BsonType autoId) in ..\LiteDB-4\LiteDB\Engine\Engine\Insert.cs:line 29
	   at LiteDB.LiteCollection`1.Insert(T document) in ..\LiteDB-4\LiteDB\Database\Collections\Insert.cs:line 18

As I debugged the process I found this segment in the class BsonMapper.Serialize.cs in the method internal BsonValue Serialize(Type type, object obj, int depth):

//// check if is a list or array
else if (obj is IEnumerable)
{
	return this.SerializeArray(Reflection.GetListItemType(obj.GetType()), obj as IEnumerable, depth);
}
// otherwise serialize as a plain object
else
{
	return this.SerializeObject(type, obj, depth);
}

As I see it when a object is IEnumerable it tries to saves ONLY It’s enumeration and ignores all the properties. And also the result from this.SerializeArray(Reflection.GetListItemType(obj.GetType()), obj as IEnumerable, depth); is not a BsonDocument and when It tries to convert to one we get the NullReferenceExeption above. If I comment out the verificaton else if (obj is IEnumerable) and jump to save the plain object I can save my IEnumerable class without problems.

It also shows why when I try to save a class that contains a property that is IEnumerable it saves it without problems. It first saves the ContainsEnumerableExample as a plain object and then saves recursively its IEnumerable property to a BsonArray. And there is no problems if a BsonArray (EnumerableExample ) is inside a BsonDocument (ContainsEnumerableExample).

The problem is when It converts a IEnumerable class to a BsonArray when it should be a BsonDocument instead.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
MarceloDMCcommented, Dec 18, 2017

Olá Mauricio!

Inicialmente eu tentei utilizar o resgistro para tipo exclusivo/customizado da BsonMapper para contornar esse problema mas sem sucesso. Com isso fui tentar descobrir o que estava de “errado” com a inserção de classes que extendem interfaces.

Com a sua resposta voltei a insistir no uso da ResgisterType e finalmente entendi o seu funcionamento. Agora consigo controlar o salvamento e o carregamento das minhas classes idependente da interface ou herença que elas venham a possuir.

Muito obrigado e um abraço da terra do pão-de-queijo! 😉

0reactions
MJLHThomassen-Eurocomcommented, Jan 4, 2018

Thanks!

Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - What is a NullReferenceException, and how do I fix it?
You are trying to use something that is null (or Nothing in VB.NET). This means you either set it to null , or...
Read more >
Object Reference Not Set to an Instance of an Object
This exception is thrown when you try to access a member—for instance, a method or a property—on a variable that currently holds a...
Read more >
c# - Is it unreasonable to expect Any() *not* to throw a null ...
I suppose you expect NullReferenceException . Any() is an extension method, it should smoothly integrate with the extended object then throwing ...
Read more >
Object reference not set to an instance of an object
A null reference means that it is trying to access something that doesn't exist. You either forgot to drag something in the editor,...
Read more >
Best Practices Implementing the IEnumerable Interface
In this article we will cover the origin, the purpose, and best practices in implementing IEnumerable interface in C#.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found