Created
September 3, 2015 18:01
-
-
Save kdbanman/34baea357f6e8203f285 to your computer and use it in GitHub Desktop.
Anonymous Class Pattern in C# - a concise, exemplary form of http://twistedoakstudios.com/blog/Post774_anonymous-implementation-classes-a-design-pattern-for-c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// So you want to use anonymous interface implementations in C#? Does this lambda-based usage look ok? | |
// Ignore the fact that "list" and "projection" are undefined here, just note the lambdas that can close | |
// around any variables and procedures you want. | |
new AnonymousReadOnlyList<TOut>( | |
count: () => list.Count, | |
item: i => projection(list[i]), | |
iterator: list.AsEnumerable().Select(projection)); | |
new AnonymousReadOnlyList<TOut>( | |
count: () => list.Count, | |
item: i => projection(list[i], i), | |
iterator: list.AsEnumerable().Select(projection)); | |
new AnonymousReadOnlyList<T>( | |
count: () => list.Count, | |
item: i => list[list.Count - 1 - i]); | |
new AnonymousReadOnlyList<TOut>( | |
count: () => Math.Min(list1.Count, list2.Count), | |
item: i => projection(list1[i], list2[i]), | |
iterator: list1.AsEnumerable().Zip(list2, projection)); | |
new AnonymousReadOnlyList<int>( | |
count: () => count, | |
item: i => i, | |
iterator: Enumerable.Range(0, count)); | |
// ... and so on. This is how: | |
// 1. Define your interface. | |
public interface IReadOnlyList<out T> : IReadOnlyCollection<T> { | |
T this[int index] { get; } | |
} | |
// 2. Provide a single not-so-concrete implementation for all anonymous implementations to use. | |
// This also shows how to provide "default methods" - GetEnumerator() here. | |
public sealed class AnonymousReadOnlyList<T> : IReadOnlyList<T> { | |
private readonly Func<int> _count; | |
private readonly Func<int, T> _item; | |
private readonly IEnumerable<T> _iterator; | |
public AnonymousReadOnlyList(Func<int> count, Func<int, T> item, IEnumerable<T> iterator = null) { | |
if (count == null) throw new ArgumentNullException("count"); | |
if (item == null) throw new ArgumentNullException("item"); | |
this._count = count; | |
this._item = item; | |
this._iterator = iterator ?? DefaultIterator(count, item); | |
} | |
private static IEnumerable<T> DefaultIterator(Func<int> count, Func<int, T> item) { | |
var n = count(); | |
for (var i = 0; i < n; i++) | |
yield return item(i); | |
} | |
public int Count { | |
get { | |
return _count(); | |
} | |
} | |
public T this[int index] { | |
get { | |
return _item(index); | |
} | |
} | |
public IEnumerator<T> GetEnumerator() { | |
return _iterator.GetEnumerator(); | |
} | |
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { | |
return GetEnumerator(); | |
} | |
} | |
// 3. Now you can create anonymous implementations with lambdas like the ones at the beginning of this gist! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment