I am looking at the Roslyn September 2012 CTP with Reflector, and I noticed that the ChildSyntaxList struct has the following:
public struct ChildSyntaxList : IEnumerable<SyntaxNodeOrToken>
{
private readonly SyntaxNode node;
private readonly int count;
public Enumerator GetEnumerator()
{
return node == null ? new Enumerator() : new Enumerator(node, count);
}
IEnumerator<SyntaxNodeOrToken> IEnumerable<SyntaxNodeOrToken>.GetEnumerator()
{
return node == null
? SpecializedCollections.EmptyEnumerator<SyntaxNodeOrToken>()
: new EnumeratorImpl(node, count);
}
IEnumerator IEnumerable.GetEnumerator()
{
return node == null
? SpecializedCollections.EmptyEnumerator<SyntaxNodeOrToken>()
: new EnumeratorImpl(node, count);
}
public struct Enumerator
{
internal Enumerator(SyntaxNode node, int count)
{
/* logic */
}
public SyntaxNodeOrToken Current { get { /* logic */ } }
public bool MoveNext()
{
/* logic */
}
public void Reset()
{
/* logic */
}
}
private class EnumeratorImpl : IEnumerator<SyntaxNodeOrToken>
{
private Enumerator enumerator;
internal EnumeratorImpl(SyntaxNode node, int count)
{
enumerator = new Enumerator(node, count);
}
public SyntaxNodeOrToken Current { get { return enumerator.Current; } }
object IEnumerator.Current { get { return enumerator.Current; } }
public void Dispose()
{
}
public bool MoveNext()
{
return enumerator.MoveNext();
}
public void Reset()
{
enumerator.Reset();
}
}
}
That is, there is a GetEnumerator
method which returns a struct.
It looks like that
List<T>.Enumerator
struct, as noted in this answer, and thatIDisposable
so as to not have to worry about bugs that could arise from doing so, as noted on Eric Lippert's blog.However, unlike the BCL List<T>
class, there is a nested EnumeratorImpl
class. Is the purpose of this to
IEnumerable<SyntaxNodeOrToken>.GetEnumerator
and IEnumerable.GetEnumerator
methods?Are there any other reasons?
During my investigations of List<T> enumeration I noticed List<T>.Enumerator is struct. In opposite for instance to System.Array.SZArrayEnumerator or System.SZArrayHelper.SZGenericArrayEnumerator<T> that are class es.
C++11 has introduced enum classes (also called scoped enumerations ), that makes enumerations both strongly typed and strongly scoped. Class enum doesn’t allow implicit conversion to int, and also doesn’t compare enumerators from different enumerations. To define enum class we use class keyword after enum keyword.
It seems this not typical usage of struct since enumerator has no traits of value type. For instance it modifies its state, it is never passed "by value" anywhere, etc. What is design intention here? Fewer allocations means less memory pressure for the garbage collector.
Class enum doesn’t allow implicit conversion to int, and also doesn’t compare enumerators from different enumerations. To define enum class we use class keyword after enum keyword. // Declaration enum class EnumName { Value1, Value2, ... ValueN}; // Initialisation EnumName ObjectName = EnumName::Value;
Are there any other reasons?
None come to mind. You seem to have accurately described the purposes of this rather odd implementation of the sequence pattern.
I hasten to add: Roslyn is an unusual .NET application in its complexity, in its performance requirements, and in the number of objects that it generates. A compiler that analyzes programs with thousands of files, millions of lines and tens of millions of characters while the user is typing has to do some pretty unusual things to ensure that it does not overwhelm the garbage collector. Roslyn therefore uses pooling strategies, uses mutable value types, and other out-of-the-mainstream practices to help achieve these performance goals. I do not recommend taking on the expense and difficulty associated with these practices unless you have empirical evidence identifying a serious performance problem that these practices mitigate. Just because this code was written by the C# compiler team does not mean that this is the gold standard for how you should be writing your mainstream business objects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With