public void VerifyTuple(int size) { //Construct a tuple of the right type MethodInfo mi = typeof(MutableTuple).GetMethod("MakeTupleType", BindingFlags.Public | BindingFlags.Static); Assert(mi != null, "Could not find Tuple.MakeTupleType"); Type[] args = new Type[size]; object[] values = new object[size]; for (int i = 0; i < size; i++) { args[i] = typeof(int); values[i] = 0; } Type tupleType = (Type)mi.Invoke(null, new object[] { args }); MutableTuple t = MutableTuple.MakeTuple(tupleType, values); ///////////////////// //Properties //Write for (int i = 0; i < size; i++) { object o = t; foreach (PropertyInfo pi in MutableTuple.GetAccessPath(tupleType, i)) { if (typeof(MutableTuple).IsAssignableFrom(pi.PropertyType)) { o = pi.GetValue(o, null); } else { pi.SetValue(o, i * 5, null); } } } //Read for (int i = 0; i < size; i++) { object o = t; foreach (PropertyInfo pi in MutableTuple.GetAccessPath(tupleType, i)) { o = pi.GetValue(o, null); } AreEqual(typeof(int), o.GetType()); AreEqual((int)o, i * 5); } //Negative cases for properties AssertError <ArgumentException>(delegate() { foreach (PropertyInfo pi in MutableTuple.GetAccessPath(tupleType, -1)) { Console.WriteLine(pi.Name); //This won't run, but we need it so that this call isn't inlined } }); ///////////////////// //GetTupleValues values = MutableTuple.GetTupleValues(t); AreEqual(values.Length, size); for (int i = 0; i < size; i++) { AreEqual(typeof(int), values[i].GetType()); AreEqual((int)(values[i]), i * 5); } ///////////////////// //Access methods if (size <= MutableTuple.MaxSize) { //SetValue for (int i = 0; i < size; i++) { t.SetValue(i, i * 3); } //GetValue for (int i = 0; i < size; i++) { AreEqual(t.GetValue(i), i * 3); } //Ensure there are no extras if (tupleType.GetGenericArguments().Length <= size) { //We're requesting an index beyond the end of this tuple. AssertError <ArgumentException>(delegate() { t.SetValue(size, 3); }); AssertError <ArgumentException>(delegate() { t.GetValue(size); }); } else { /*We're requesting an index in the scope of this tuple but beyond the scope of our * requested capacity (in which case the field's type will be Microsoft.Scripting.None * and we won't be able to convert "3" to that). Imagine asking for a tuple of 3 ints, * we'd actually get a Tuple<int,int,int,Microsoft.Scripting.None> since there is no * Tuple that takes only 3 generic arguments.*/ AssertError <InvalidCastException>(delegate() { t.SetValue(size, 3); }); //Verify the type of the field AreEqual(typeof(Microsoft.Scripting.Runtime.DynamicNull), tupleType.GetGenericArguments()[size]); //Verify the value of the field is null AreEqual(null, t.GetValue(size)); } } }