/// <summary> /// Sets the data for the specified class at the specified index. If the class has /// changed then a full look for the slot will be performed. If the new class does /// not have the provided slot then the Expando's class will change. Only case sensitive /// setter is supported in ExpandoObject. /// </summary> internal int TrySetValue(ExpandoClass klass, int index, object value, bool caseInsensitive) { Debug.Assert(index >= 0); lock (LockObject) { ExpandoData data = _data; if (data.Class != klass || caseInsensitive) { //the class has changed or we are doing a case-insensitive search, //we need to get the correct index and set the value there. If we //don't have the value then we need to promote the class - that //should only happen when we have multiple concurrent writers. string name = klass.GetIndexName(index); index = data.Class.GetValueIndex(name, caseInsensitive, this); if (index == ExpandoObject.AmbiguousMatchFound) { return index; } if (index == ExpandoObject.NoMatch) { //Before creating a new class with the new member, need to check //if there is the exact same member but is deleted. We should reuse //the class if there is such a member. int exactMatch = caseInsensitive ? data.Class.GetValueIndexCaseSensitive(name) : index; if (exactMatch != ExpandoObject.NoMatch) { Debug.Assert(data.Data[exactMatch] == Uninitialized); index = exactMatch; } else { ExpandoClass newClass = data.Class.FindNewClass(name); data = PromoteClassWorker(data.Class, newClass); //After the class promotion, there must be an exact match, //so we can do case-sensitive search here. index = data.Class.GetValueIndexCaseSensitive(name); Debug.Assert(index != ExpandoObject.NoMatch); } } } data.Data[index] = value; return index; } }
/// <summary> /// Deletes the data stored for the specified class at the specified index. /// </summary> internal int TryDeleteValue(ExpandoClass klass, int index, bool caseInsensitive) { if (index == ExpandoObject.NoMatch) { return index; } lock (LockObject) { ExpandoData data = _data; if (data.Class != klass || caseInsensitive) { // the class has changed or we are doing a case-insensitive search, // we need to get the correct index. If there is no associated index // we simply can't have the value and we return false. index = data.Class.GetValueIndex(klass.GetIndexName(index), caseInsensitive, this); if (index < 0) { return index; } } object oldValue = data.Data[index]; data.Data[index] = Uninitialized; return oldValue == Uninitialized ? ExpandoObject.NoMatch : index; } }