using System; using System.Collections; using System.Collections.Generic; public class ContainerTest { // Test 1: Variable scopes // Test 1a: Private field private IList c1a = new List { 1, 2 }; // BAD: private // Test 1b: protected field protected IList c1b = new List { 1, 2 }; // GOOD: protected // Test 1c: public field public IList c1c = new List { 1, 2 }; // GOOD: public // Test 1d: internal field internal IList c1d = new List { 1, 2 }; // BAD: internal void TestScopes() { c1a.Add(1); c1b.Add(2); c1c.Add(3); c1d.Add(4); // Test 1e: Local variable IList c1e = new List { 1, 2 }; // BAD: local c1e.Add(5); } // Test 2: Method names void TestMethodNames() { // Test 2a: Writeonly method names IList c2a = new List { 1, 2 }; // BAD: writeonly methods c2a.Add(1); c2a.Clear(); c2a.Insert(1, 2); c2a.Remove(1); c2a.RemoveAt(3); // Test 2b: Read/write method names IList c2b = new List { 1, 2 }; // GOOD: read method bool b = c2b.Contains(1); // Test 2c: Other method names var c2c = new Stack(); // BAD c2c.Push(1); var c2d = new BitArray(10); // BAD c2d.Set(1, true); c2d.SetAll(false); var c2j = new LinkedList(); // BAD c2j.AddFirst(1); c2j.AddLast(2); c2j.RemoveFirst(); c2j.RemoveLast(); } // Test 3: Variable uses IList f() { return new List(); } void f(IList x) { } IList g() { // Returned from function var c3c = new List { 2, 3, 4 }; // GOOD: returned c3c.Add(5); return c3c; } IList h { get { // Returned from property var c3d = new List(); // GOOD: returned c3d.Add(1); return c3d; } } IList this[int i] { get { // Returned from property var c3e = new List(); // GOOD: returned c3e.Add(1); return c3e; } } void TestAccessTypes() { // 3a: Unused IList c3a = new List { 4, 5 }; // BAD // 3b: Pass to function IList c3b = new List { }; // GOOD: used c3b.Add(1); f(c3b); // 3f: Access a property var c3f = new List(); // GOOD: accessed c3f.Add(1); int zero = c3f.Count; } // Test 4: Initialization type private IList c4a; // BAD: even though uninitialized void TestInitializationTypes() { // Test 4a: Uninitialized c4a.Add(1); // Test 4b: Constructed from new var c4b = new List(); // BAD c4b.Add(1); // Test 4c: List initialized var c4c = new List { 2, 3, 4 }; // BAD c4c.Add(1); // Test 4d: Constructed from other expression var c4d = f(); // GOOD c4d.Add(1); // Test 4e: In a foreach loop List> c4e = new List> { new List { "x" } }; foreach (var c4f in c4e) // GOOD: constructed from elsewehere c4f.Remove("x"); int x = c4e.Count; } // Test 5: Assignment void TestAssignment() { // Assigned from new container IList c5a; // BAD c5a = new List(); c5a.Add(1); // Assigned from something else IList c5b; // GOOD: from f() c5b = f(); c5b.Add(1); // Assigned to something IList c5c = new List(), c5d; // GOOD: assigned elsewhere c5c.Add(1); c5d = c5c; // Assigned in an expression somewhere IList c5e = new List(); // BAD: assigned in expr for (int i = 0; i < 10; c5e = new List(), ++i) c5e.Add(1); IList c5f = new List(); // GOOD: assigned in expr for (int i = 0; i < 10; c5f = null, ++i) c5f.Add(1); } class NonCollection { public void Add(int i) { } } // Test 6: Collection type void TestCollections() { var c6a = new NonCollection(); // GOOD: not a collection c6a.Add(1); var c6b = new ArrayList(); // BAD c6b.Add(1); var c6c = new BitArray(32); // BAD c6c.SetAll(true); var c6d = new Hashtable(); // BAD c6d.Add(1, 2); var c6e = new Queue(); // BAD c6e.Enqueue(1); var c6f = new SortedList(); // BAD c6f.Add(1, 2); var c6g = new Stack(); // BAD c6g.Push(1); var c6h = new Dictionary(); // BAD c6h.Add(1, 2); var c6i = new HashSet(); // BAD c6i.Add(1); var c6j = new LinkedList(); // BAD c6j.AddFirst(1); var c6k = new List(); // BAD c6k.Add(1); var c6l = new Queue(); // BAD c6l.Enqueue(1); var c6m = new SortedDictionary(); // BAD c6m.Add(1, 2); var c6n = new SortedList(); // BAD c6n.Add(1, 2); var c6o = new SortedDictionary(); // BAD c6o.Add(1, 2); var c6p = new SortedSet(); // BAD c6p.Add(1); var c6q = new Stack(); // BAD c6q.Push(1); ICollection c6u = new List(); // BAD c6u.Add(1); IDictionary c6v = new Dictionary(); // BAD c6v.Add(1, 2); IEnumerable c6w = new List(); // GOOD c6w.GetEnumerator(); IList c6x = new List(); // BAD c6x.Add(12); ISet c6y = new HashSet(); // BAD c6y.Add(1); } void TestDynamicAccess() { // GOOD: dynamic dynamic c7a = new List(); c7a.Add(1); // GOOD: cast to dynamic var c7b = new List(); c7b.Add(1); dynamic x = (dynamic)c7b; // GOOD: passed as param to InvokeMember var c7c = new List(); var t = typeof(List); t.InvokeMember("Add", System.Reflection.BindingFlags.InvokeMethod, null, c7c, new Object[] { 1 }); } IList c8a = new List(); // BAD: no attribute [Obsolete()] IList c8b = new List(); // GOOD: has attribute void TestAttributes() { c8a.Add(1); c8b.Add(2); } public static void Main(string[] args) { ContainerTest t = new ContainerTest(); } IEnumerable> TestIndirectInitializations(IList[] stringss) { foreach (var strings in stringss) strings.Add(""); // GOOD if (stringss[0] is List l) l.Add(""); // GOOD switch (stringss[0]) { case List l2: l2.Add(""); // GOOD break; } return stringss; } void Out(out List strings) { strings = new List { "a", "b", "c" }; } void OutTest() { Out(out var strings); // BAD: but allow for now (only C# 7 allows discards) } }