You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -0,0 +1,269 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="BitVector32.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Collections.Specialized {
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System;
|
||||
using Microsoft.Win32;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Provides a simple light bit vector with easy integer or Boolean access to
|
||||
/// a 32 bit storage.</para>
|
||||
/// </devdoc>
|
||||
public struct BitVector32 {
|
||||
private uint data;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Initializes a new instance of the BitVector32 structure with the specified internal data.</para>
|
||||
/// </devdoc>
|
||||
public BitVector32(int data) {
|
||||
this.data = (uint)data;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Initializes a new instance of the BitVector32 structure with the information in the specified
|
||||
/// value.</para>
|
||||
/// </devdoc>
|
||||
public BitVector32(BitVector32 value) {
|
||||
this.data = value.data;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets or sets a value indicating whether all the specified bits are set.</para>
|
||||
/// </devdoc>
|
||||
public bool this[int bit] {
|
||||
get {
|
||||
return (data & bit) == (uint)bit;
|
||||
}
|
||||
set {
|
||||
if (value) {
|
||||
data |= (uint)bit;
|
||||
}
|
||||
else {
|
||||
data &= ~(uint)bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets or sets the value for the specified section.</para>
|
||||
/// </devdoc>
|
||||
public int this[Section section] {
|
||||
get {
|
||||
return (int)((data & (uint)(section.Mask << section.Offset)) >> section.Offset);
|
||||
}
|
||||
set {
|
||||
#if DEBUG
|
||||
if ((value & section.Mask) != value) {
|
||||
Debug.Fail("Value out of bounds on BitVector32 Section Set!");
|
||||
}
|
||||
#endif
|
||||
value <<= section.Offset;
|
||||
int offsetMask = (0xFFFF & (int)section.Mask) << section.Offset;
|
||||
data = (data & ~(uint)offsetMask) | ((uint)value & (uint)offsetMask);
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// returns the raw data stored in this bit vector...
|
||||
/// </devdoc>
|
||||
public int Data {
|
||||
get {
|
||||
return (int)data;
|
||||
}
|
||||
}
|
||||
|
||||
private static short CountBitsSet(short mask) {
|
||||
|
||||
// yes, I know there are better algorithms, however, we know the
|
||||
// bits are always right aligned, with no holes (i.e. always 00000111,
|
||||
// never 000100011), so this is just fine...
|
||||
//
|
||||
short value = 0;
|
||||
while ((mask & 0x1) != 0) {
|
||||
value++;
|
||||
mask >>= 1;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para> Creates the first mask in a series.</para>
|
||||
/// </devdoc>
|
||||
public static int CreateMask() {
|
||||
return CreateMask(0);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Creates the next mask in a series.
|
||||
/// </devdoc>
|
||||
public static int CreateMask(int previous) {
|
||||
if (previous == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (previous == unchecked((int)0x80000000)) {
|
||||
throw new InvalidOperationException(SR.GetString(SR.BitVectorFull));
|
||||
}
|
||||
|
||||
return previous << 1;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// Given a highValue, creates the mask
|
||||
/// </devdoc>
|
||||
private static short CreateMaskFromHighValue(short highValue) {
|
||||
short required = 16;
|
||||
while ((highValue & 0x8000) == 0) {
|
||||
required--;
|
||||
highValue <<= 1;
|
||||
}
|
||||
|
||||
ushort value = 0;
|
||||
while (required > 0) {
|
||||
required--;
|
||||
value <<= 1;
|
||||
value |= 0x1;
|
||||
}
|
||||
|
||||
return unchecked((short) value);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Creates the first section in a series, with the specified maximum value.</para>
|
||||
/// </devdoc>
|
||||
public static Section CreateSection(short maxValue) {
|
||||
return CreateSectionHelper(maxValue, 0, 0);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Creates the next section in a series, with the specified maximum value.</para>
|
||||
/// </devdoc>
|
||||
public static Section CreateSection(short maxValue, Section previous) {
|
||||
return CreateSectionHelper(maxValue, previous.Mask, previous.Offset);
|
||||
}
|
||||
|
||||
private static Section CreateSectionHelper(short maxValue, short priorMask, short priorOffset) {
|
||||
if (maxValue < 1) {
|
||||
throw new ArgumentException(SR.GetString(SR.Argument_InvalidValue, "maxValue", 0), "maxValue");
|
||||
}
|
||||
#if DEBUG
|
||||
int maskCheck = CreateMaskFromHighValue(maxValue);
|
||||
int offsetCheck = priorOffset + CountBitsSet(priorMask);
|
||||
Debug.Assert(maskCheck <= short.MaxValue && offsetCheck < 32, "Overflow on BitVector32");
|
||||
#endif
|
||||
short offset = (short)(priorOffset + CountBitsSet(priorMask));
|
||||
if (offset >= 32) {
|
||||
throw new InvalidOperationException(SR.GetString(SR.BitVectorFull));
|
||||
}
|
||||
return new Section(CreateMaskFromHighValue(maxValue), offset);
|
||||
}
|
||||
|
||||
public override bool Equals(object o) {
|
||||
if (!(o is BitVector32)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return data == ((BitVector32)o).data;
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return base.GetHashCode();
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// </devdoc>
|
||||
public static string ToString(BitVector32 value) {
|
||||
StringBuilder sb = new StringBuilder(/*"BitVector32{".Length*/12 + /*32 bits*/32 + /*"}".Length"*/1);
|
||||
sb.Append("BitVector32{");
|
||||
int locdata = (int)value.data;
|
||||
for (int i=0; i<32; i++) {
|
||||
if ((locdata & 0x80000000) != 0) {
|
||||
sb.Append("1");
|
||||
}
|
||||
else {
|
||||
sb.Append("0");
|
||||
}
|
||||
locdata <<= 1;
|
||||
}
|
||||
sb.Append("}");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// </devdoc>
|
||||
public override string ToString() {
|
||||
return BitVector32.ToString(this);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Represents an section of the vector that can contain a integer number.</para>
|
||||
/// </devdoc>
|
||||
public struct Section {
|
||||
private readonly short mask;
|
||||
private readonly short offset;
|
||||
|
||||
internal Section(short mask, short offset) {
|
||||
this.mask = mask;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public short Mask {
|
||||
get {
|
||||
return mask;
|
||||
}
|
||||
}
|
||||
|
||||
public short Offset {
|
||||
get {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object o) {
|
||||
if (o is Section)
|
||||
return Equals((Section)o);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(Section obj)
|
||||
{
|
||||
return obj.mask == mask && obj.offset == offset;
|
||||
}
|
||||
|
||||
public static bool operator ==(Section a, Section b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
public static bool operator !=(Section a, Section b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
public override int GetHashCode() {
|
||||
return base.GetHashCode();
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// </devdoc>
|
||||
public static string ToString(Section value) {
|
||||
return "Section{0x" + Convert.ToString(value.Mask, 16) + ", 0x" + Convert.ToString(value.Offset, 16) + "}";
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// </devdoc>
|
||||
public override string ToString() {
|
||||
return Section.ToString(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="CaseSensitiveStringDictionary.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
On UNIX systems the environment variable names are case sensitive (as the opposite from Windows).
|
||||
Thus using StringDictionary to store the environment settings is wrong
|
||||
(StringDictionary converts key values to lower case).
|
||||
CaseSensitiveStringDictionary is derived from the StringDictionary and it does the same thing,
|
||||
except the conversion of the key to lower case. So its fully usable for UNIX systems.
|
||||
This class is used to create the StringDictionary object everywhere
|
||||
its used for environment settings storage (only ProcessStartInfo.cs and Executor.cs).
|
||||
This change enables the correct UNIX behavior along with not changing public API.
|
||||
Author: vitkaras
|
||||
*/
|
||||
|
||||
#if PLATFORM_UNIX
|
||||
|
||||
namespace System.Collections.Specialized
|
||||
{
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Diagnostics;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.ComponentModel.Design.Serialization;
|
||||
using System.Globalization;
|
||||
using System.Security.Permissions;
|
||||
|
||||
// This subclass of StringDictionary ensures that we do the lookups in a case-sensitive manner,
|
||||
// so we can match any string comparisons that are done on Unix.
|
||||
internal class CaseSensitiveStringDictionary : StringDictionary
|
||||
{
|
||||
public CaseSensitiveStringDictionary () {
|
||||
}
|
||||
|
||||
public override string this[ string key ]
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( key == null )
|
||||
{
|
||||
throw new ArgumentNullException ( "key" );
|
||||
}
|
||||
|
||||
return (string) contents[ key ];
|
||||
}
|
||||
set
|
||||
{
|
||||
if ( key == null )
|
||||
{
|
||||
throw new ArgumentNullException ( "key" );
|
||||
}
|
||||
|
||||
contents[ key ] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Add ( string key, string value )
|
||||
{
|
||||
if ( key == null )
|
||||
{
|
||||
throw new ArgumentNullException ( "key" );
|
||||
}
|
||||
|
||||
contents.Add ( key , value );
|
||||
}
|
||||
|
||||
public override bool ContainsKey ( string key )
|
||||
{
|
||||
if ( key == null )
|
||||
{
|
||||
throw new ArgumentNullException ( "key" );
|
||||
}
|
||||
|
||||
return contents.ContainsKey ( key );
|
||||
}
|
||||
|
||||
public override void Remove ( string key )
|
||||
{
|
||||
if ( key == null )
|
||||
{
|
||||
throw new ArgumentNullException ( "key" );
|
||||
}
|
||||
|
||||
contents.Remove ( key );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // PLATFORM_UNIX
|
||||
@@ -0,0 +1,48 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="CollectionsUtil.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Wrapper for a case insensitive Hashtable.
|
||||
|
||||
namespace System.Collections.Specialized {
|
||||
|
||||
using System.Collections;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public class CollectionsUtil {
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public static Hashtable CreateCaseInsensitiveHashtable() {
|
||||
return new Hashtable(StringComparer.CurrentCultureIgnoreCase);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public static Hashtable CreateCaseInsensitiveHashtable(int capacity) {
|
||||
return new Hashtable(capacity, StringComparer.CurrentCultureIgnoreCase);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public static Hashtable CreateCaseInsensitiveHashtable(IDictionary d) {
|
||||
return new Hashtable(d, StringComparer.CurrentCultureIgnoreCase);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public static SortedList CreateCaseInsensitiveSortedList() {
|
||||
return new SortedList(CaseInsensitiveComparer.Default);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="FixedStringLookup.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Collections.Specialized {
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
|
||||
// This class provides a very efficient way to lookup an entry in a list of strings,
|
||||
// providing that they are declared in a particular way.
|
||||
|
||||
// It requires the set of strings to be orderded into an array of arrays of strings.
|
||||
// The first indexer must the length of the string, so that each sub-array is of the
|
||||
// same length. The contained array must be in alphabetical order. Furthermore, if the
|
||||
// table is to be searched case-insensitively, the strings must all be lower case.
|
||||
internal static class FixedStringLookup {
|
||||
|
||||
// Returns whether the match is found in the lookup table
|
||||
internal static bool Contains(string[][] lookupTable, string value, bool ignoreCase) {
|
||||
int length = value.Length;
|
||||
if (length <= 0 || length - 1 >= lookupTable.Length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string[] subArray = lookupTable[length - 1];
|
||||
if (subArray == null) {
|
||||
return false;
|
||||
}
|
||||
return Contains(subArray, value, ignoreCase);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
internal static void VerifyLookupTable(string[][] lookupTable, bool ignoreCase) {
|
||||
for (int i = 0; i < lookupTable.Length; i++) {
|
||||
string[] subArray = lookupTable[i];
|
||||
if (subArray != null) {
|
||||
string lastValue = null;
|
||||
for (int j = 0; j < subArray.Length; j++) {
|
||||
string value = subArray[j];
|
||||
// Must all be the length of the hashed position
|
||||
Debug.Assert(value.Length == i + 1, "Lookup table contains an item in the wrong subtable. Item name: " + value);
|
||||
if (lastValue != null) {
|
||||
// Must be sorted within the sub array;
|
||||
Debug.Assert(string.Compare(lastValue, value, ((ignoreCase) ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) < 0,
|
||||
String.Format(CultureInfo.InvariantCulture, "Lookup table is out of order. Items {0} and {1} are reversed", lastValue, value));
|
||||
}
|
||||
lastValue = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// This routine finds a hit within a single sorted array, with the assumption that the
|
||||
// value and all the strings are of the same length.
|
||||
private static bool Contains(string[] array, string value, bool ignoreCase) {
|
||||
int min = 0;
|
||||
int max = array.Length;
|
||||
int pos = 0;
|
||||
char searchChar;
|
||||
while (pos < value.Length) {
|
||||
if (ignoreCase) {
|
||||
searchChar = char.ToLower(value[pos], CultureInfo.InvariantCulture);
|
||||
} else {
|
||||
searchChar = value[pos];
|
||||
}
|
||||
if ((max - min) <= 1) {
|
||||
// we are down to a single item, so we can stay on this row until the end.
|
||||
if (searchChar != array[min][pos]) {
|
||||
return false;
|
||||
}
|
||||
pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// There are multiple items to search, use binary search to find one of the hits
|
||||
if (!FindCharacter(array, searchChar, pos, ref min, ref max)) {
|
||||
return false;
|
||||
}
|
||||
// and move to next char
|
||||
pos++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Do a binary search on the character array at the specific position and constrict the ranges appropriately.
|
||||
private static bool FindCharacter(string[] array, char value, int pos, ref int min, ref int max) {
|
||||
int index = min;
|
||||
while (min < max) {
|
||||
index = (min + max) / 2;
|
||||
char comp = array[index][pos];
|
||||
if (value == comp) {
|
||||
// We have a match. Now adjust to any adjacent matches
|
||||
int newMin = index;
|
||||
while (newMin > min && array[newMin - 1][pos] == value) {
|
||||
newMin--;
|
||||
}
|
||||
min = newMin;
|
||||
|
||||
int newMax = index + 1;
|
||||
while (newMax < max && array[newMax][pos] == value) {
|
||||
newMax++;
|
||||
}
|
||||
max = newMax;
|
||||
return true;
|
||||
}
|
||||
if (value < comp) {
|
||||
max = index;
|
||||
}
|
||||
else {
|
||||
min = index + 1;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,338 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="HybridDictionary.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Collections.Specialized {
|
||||
|
||||
using System.Collections;
|
||||
using System.Globalization;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// This data structure implements IDictionary first using a linked list
|
||||
/// (ListDictionary) and then switching over to use Hashtable when large. This is recommended
|
||||
/// for cases where the number of elements in a dictionary is unknown and might be small.
|
||||
///
|
||||
/// It also has a single boolean parameter to allow case-sensitivity that is not affected by
|
||||
/// ambient culture and has been optimized for looking up case-insensitive symbols
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
[Serializable]
|
||||
public class HybridDictionary: IDictionary {
|
||||
|
||||
// These numbers have been carefully tested to be optimal. Please don't change them
|
||||
// without doing thorough performance testing.
|
||||
private const int CutoverPoint = 9;
|
||||
private const int InitialHashtableSize = 13;
|
||||
private const int FixedSizeCutoverPoint = 6;
|
||||
|
||||
// Instance variables. This keeps the HybridDictionary very light-weight when empty
|
||||
private ListDictionary list;
|
||||
private Hashtable hashtable;
|
||||
private bool caseInsensitive;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public HybridDictionary() {
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public HybridDictionary(int initialSize) : this(initialSize, false) {
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public HybridDictionary(bool caseInsensitive) {
|
||||
this.caseInsensitive = caseInsensitive;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public HybridDictionary(int initialSize, bool caseInsensitive) {
|
||||
this.caseInsensitive = caseInsensitive;
|
||||
if (initialSize >= FixedSizeCutoverPoint) {
|
||||
if (caseInsensitive) {
|
||||
hashtable = new Hashtable(initialSize, StringComparer.OrdinalIgnoreCase);
|
||||
} else {
|
||||
hashtable = new Hashtable(initialSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public object this[object key] {
|
||||
get {
|
||||
// <
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ListDictionary cachedList = list;
|
||||
if (hashtable != null) {
|
||||
return hashtable[key];
|
||||
} else if (cachedList != null) {
|
||||
return cachedList[key];
|
||||
} else {
|
||||
// <
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
set {
|
||||
if (hashtable != null) {
|
||||
hashtable[key] = value;
|
||||
}
|
||||
else if (list != null) {
|
||||
if (list.Count >= CutoverPoint - 1) {
|
||||
ChangeOver();
|
||||
hashtable[key] = value;
|
||||
} else {
|
||||
list[key] = value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
|
||||
list[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ListDictionary List {
|
||||
get {
|
||||
if (list == null) {
|
||||
list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
private void ChangeOver() {
|
||||
IDictionaryEnumerator en = list.GetEnumerator();
|
||||
Hashtable newTable;
|
||||
if (caseInsensitive) {
|
||||
newTable = new Hashtable(InitialHashtableSize, StringComparer.OrdinalIgnoreCase);
|
||||
} else {
|
||||
newTable = new Hashtable(InitialHashtableSize);
|
||||
}
|
||||
while (en.MoveNext()) {
|
||||
newTable.Add(en.Key, en.Value);
|
||||
}
|
||||
// <
|
||||
|
||||
|
||||
|
||||
|
||||
hashtable = newTable;
|
||||
list = null;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public int Count {
|
||||
get {
|
||||
ListDictionary cachedList = list;
|
||||
if (hashtable != null) {
|
||||
return hashtable.Count;
|
||||
} else if (cachedList != null) {
|
||||
return cachedList.Count;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public ICollection Keys {
|
||||
get {
|
||||
if (hashtable != null) {
|
||||
return hashtable.Keys;
|
||||
} else {
|
||||
return List.Keys;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool IsReadOnly {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool IsFixedSize {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool IsSynchronized {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public object SyncRoot {
|
||||
get {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public ICollection Values {
|
||||
get {
|
||||
if (hashtable != null) {
|
||||
return hashtable.Values;
|
||||
} else {
|
||||
return List.Values;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public void Add(object key, object value) {
|
||||
if (hashtable != null) {
|
||||
hashtable.Add(key, value);
|
||||
} else {
|
||||
if (list == null) {
|
||||
list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
|
||||
list.Add(key, value);
|
||||
}
|
||||
else {
|
||||
if (list.Count + 1 >= CutoverPoint) {
|
||||
ChangeOver();
|
||||
hashtable.Add(key, value);
|
||||
} else {
|
||||
list.Add(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public void Clear() {
|
||||
if(hashtable != null) {
|
||||
Hashtable cachedHashtable = hashtable;
|
||||
hashtable = null;
|
||||
cachedHashtable.Clear();
|
||||
}
|
||||
|
||||
if( list != null) {
|
||||
ListDictionary cachedList = list;
|
||||
list = null;
|
||||
cachedList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool Contains(object key) {
|
||||
ListDictionary cachedList = list;
|
||||
if (hashtable != null) {
|
||||
return hashtable.Contains(key);
|
||||
} else if (cachedList != null) {
|
||||
return cachedList.Contains(key);
|
||||
} else {
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public void CopyTo(Array array, int index) {
|
||||
if (hashtable != null) {
|
||||
hashtable.CopyTo(array, index);
|
||||
} else {
|
||||
List.CopyTo(array, index);
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public IDictionaryEnumerator GetEnumerator() {
|
||||
if (hashtable != null) {
|
||||
return hashtable.GetEnumerator();
|
||||
}
|
||||
if (list == null) {
|
||||
list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
|
||||
}
|
||||
return list.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
if (hashtable != null) {
|
||||
return hashtable.GetEnumerator();
|
||||
}
|
||||
if (list == null) {
|
||||
list = new ListDictionary(caseInsensitive ? StringComparer.OrdinalIgnoreCase : null);
|
||||
}
|
||||
return list.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public void Remove(object key) {
|
||||
if (hashtable != null) {
|
||||
hashtable.Remove(key);
|
||||
}
|
||||
else if (list != null){
|
||||
list.Remove(key);
|
||||
}
|
||||
else {
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// <copyright file="INotifyCollectionChanged.cs" company="Microsoft">
|
||||
// Copyright (C) 2003 by Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
//
|
||||
// Description: Allows collections to notify listeners of dynamic updates.
|
||||
//
|
||||
// See spec at http://avalon/connecteddata/Specs/INotifyCollectionChanged.mht
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Collections.Specialized
|
||||
{
|
||||
/// <summary>
|
||||
/// A collection implementing this interface will notify listeners of dynamic changes,
|
||||
/// e.g. when items get added and removed or the whole list is refreshed.
|
||||
/// </summary>
|
||||
#if !MOBILE
|
||||
[TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
|
||||
#endif
|
||||
public interface INotifyCollectionChanged
|
||||
{
|
||||
/// <summary>
|
||||
/// Occurs when the collection changes, either by adding or removing an item.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The event handler receives an argument of type
|
||||
/// <seealso cref="System.Collections.Specialized.NotifyCollectionChangedEventArgs" />
|
||||
/// containing data related to this event.
|
||||
/// </remarks>
|
||||
event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="IOrderedDictionary.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Collections.Specialized {
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// This interface adds indexing on the IDictionary keyed table concept. Objects
|
||||
/// added or inserted in an IOrderedDictionary must have both a key and an index, and
|
||||
/// can be retrieved by either.
|
||||
/// This interface is useful when preserving easy IDictionary access semantics via a key is
|
||||
/// desired while ordering is necessary.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
public interface IOrderedDictionary : IDictionary {
|
||||
|
||||
// properties
|
||||
/// <devdoc>
|
||||
/// Returns the object at the given index
|
||||
/// </devdoc>
|
||||
object this[int index] { get; set; }
|
||||
|
||||
// Returns an IDictionaryEnumerator for this dictionary.
|
||||
new IDictionaryEnumerator GetEnumerator();
|
||||
|
||||
// methods
|
||||
/// <devdoc>
|
||||
/// Inserts the given object, with the given key, at the given index
|
||||
/// </devdoc>
|
||||
void Insert(int index, object key, object value);
|
||||
|
||||
/// <devdoc>
|
||||
/// Removes the object and key at the given index
|
||||
/// </devdoc>
|
||||
void RemoveAt(int index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,455 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="ListDictionary.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Collections.Specialized {
|
||||
|
||||
using System.Collections;
|
||||
using Microsoft.Win32;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// This is a simple implementation of IDictionary using a singly linked list. This
|
||||
/// will be smaller and faster than a Hashtable if the number of elements is 10 or less.
|
||||
/// This should not be used if performance is important for large numbers of elements.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
[Serializable]
|
||||
public class ListDictionary: IDictionary {
|
||||
DictionaryNode head;
|
||||
int version;
|
||||
int count;
|
||||
IComparer comparer;
|
||||
[NonSerialized]
|
||||
private Object _syncRoot;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public ListDictionary() {
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public ListDictionary(IComparer comparer) {
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public object this[object key] {
|
||||
get {
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
|
||||
}
|
||||
DictionaryNode node = head;
|
||||
if (comparer == null) {
|
||||
while (node != null) {
|
||||
object oldKey = node.key;
|
||||
if ( oldKey!= null && oldKey.Equals(key)) {
|
||||
return node.value;
|
||||
}
|
||||
node = node.next;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (node != null) {
|
||||
object oldKey = node.key;
|
||||
if (oldKey != null && comparer.Compare(oldKey, key) == 0) {
|
||||
return node.value;
|
||||
}
|
||||
node = node.next;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
set {
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
|
||||
}
|
||||
version++;
|
||||
DictionaryNode last = null;
|
||||
DictionaryNode node;
|
||||
for (node = head; node != null; node = node.next) {
|
||||
object oldKey = node.key;
|
||||
if ((comparer == null) ? oldKey.Equals(key) : comparer.Compare(oldKey, key) == 0) {
|
||||
break;
|
||||
}
|
||||
last = node;
|
||||
}
|
||||
if (node != null) {
|
||||
// Found it
|
||||
node.value = value;
|
||||
return;
|
||||
}
|
||||
// Not found, so add a new one
|
||||
DictionaryNode newNode = new DictionaryNode();
|
||||
newNode.key = key;
|
||||
newNode.value = value;
|
||||
if (last != null) {
|
||||
last.next = newNode;
|
||||
}
|
||||
else {
|
||||
head = newNode;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public int Count {
|
||||
get {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public ICollection Keys {
|
||||
get {
|
||||
return new NodeKeyValueCollection(this, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool IsReadOnly {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool IsFixedSize {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool IsSynchronized {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public object SyncRoot {
|
||||
get {
|
||||
if( _syncRoot == null) {
|
||||
System.Threading.Interlocked.CompareExchange(ref _syncRoot, new Object(), null);
|
||||
}
|
||||
return _syncRoot;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public ICollection Values {
|
||||
get {
|
||||
return new NodeKeyValueCollection(this, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public void Add(object key, object value) {
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
|
||||
}
|
||||
version++;
|
||||
DictionaryNode last = null;
|
||||
DictionaryNode node;
|
||||
for (node = head; node != null; node = node.next) {
|
||||
object oldKey = node.key;
|
||||
if ((comparer == null) ? oldKey.Equals(key) : comparer.Compare(oldKey, key) == 0) {
|
||||
throw new ArgumentException(SR.GetString(SR.Argument_AddingDuplicate));
|
||||
}
|
||||
last = node;
|
||||
}
|
||||
// Not found, so add a new one
|
||||
DictionaryNode newNode = new DictionaryNode();
|
||||
newNode.key = key;
|
||||
newNode.value = value;
|
||||
if (last != null) {
|
||||
last.next = newNode;
|
||||
}
|
||||
else {
|
||||
head = newNode;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public void Clear() {
|
||||
count = 0;
|
||||
head = null;
|
||||
version++;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool Contains(object key) {
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
|
||||
}
|
||||
for (DictionaryNode node = head; node != null; node = node.next) {
|
||||
object oldKey = node.key;
|
||||
if ((comparer == null) ? oldKey.Equals(key) : comparer.Compare(oldKey, key) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public void CopyTo(Array array, int index) {
|
||||
if (array==null)
|
||||
throw new ArgumentNullException("array");
|
||||
if (index < 0)
|
||||
throw new ArgumentOutOfRangeException("index", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNum));
|
||||
|
||||
if (array.Length - index < count)
|
||||
throw new ArgumentException(SR.GetString(SR.Arg_InsufficientSpace));
|
||||
|
||||
for (DictionaryNode node = head; node != null; node = node.next) {
|
||||
array.SetValue(new DictionaryEntry(node.key, node.value), index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public IDictionaryEnumerator GetEnumerator() {
|
||||
return new NodeEnumerator(this);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return new NodeEnumerator(this);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public void Remove(object key) {
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key", SR.GetString(SR.ArgumentNull_Key));
|
||||
}
|
||||
version++;
|
||||
DictionaryNode last = null;
|
||||
DictionaryNode node;
|
||||
for (node = head; node != null; node = node.next) {
|
||||
object oldKey = node.key;
|
||||
if ((comparer == null) ? oldKey.Equals(key) : comparer.Compare(oldKey, key) == 0) {
|
||||
break;
|
||||
}
|
||||
last = node;
|
||||
}
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
if (node == head) {
|
||||
head = node.next;
|
||||
} else {
|
||||
last.next = node.next;
|
||||
}
|
||||
count--;
|
||||
}
|
||||
|
||||
private class NodeEnumerator : IDictionaryEnumerator {
|
||||
ListDictionary list;
|
||||
DictionaryNode current;
|
||||
int version;
|
||||
bool start;
|
||||
|
||||
|
||||
public NodeEnumerator(ListDictionary list) {
|
||||
this.list = list;
|
||||
version = list.version;
|
||||
start = true;
|
||||
current = null;
|
||||
}
|
||||
|
||||
public object Current {
|
||||
get {
|
||||
return Entry;
|
||||
}
|
||||
}
|
||||
|
||||
public DictionaryEntry Entry {
|
||||
get {
|
||||
if (current == null) {
|
||||
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumOpCantHappen));
|
||||
}
|
||||
return new DictionaryEntry(current.key, current.value);
|
||||
}
|
||||
}
|
||||
|
||||
public object Key {
|
||||
get {
|
||||
if (current == null) {
|
||||
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumOpCantHappen));
|
||||
}
|
||||
return current.key;
|
||||
}
|
||||
}
|
||||
|
||||
public object Value {
|
||||
get {
|
||||
if (current == null) {
|
||||
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumOpCantHappen));
|
||||
}
|
||||
return current.value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool MoveNext() {
|
||||
if (version != list.version) {
|
||||
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
|
||||
}
|
||||
if (start) {
|
||||
current = list.head;
|
||||
start = false;
|
||||
}
|
||||
else if (current != null) {
|
||||
current = current.next;
|
||||
}
|
||||
return (current != null);
|
||||
}
|
||||
|
||||
public void Reset() {
|
||||
if (version != list.version) {
|
||||
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
|
||||
}
|
||||
start = true;
|
||||
current = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class NodeKeyValueCollection : ICollection {
|
||||
ListDictionary list;
|
||||
bool isKeys;
|
||||
|
||||
public NodeKeyValueCollection(ListDictionary list, bool isKeys) {
|
||||
this.list = list;
|
||||
this.isKeys = isKeys;
|
||||
}
|
||||
|
||||
void ICollection.CopyTo(Array array, int index) {
|
||||
if (array==null)
|
||||
throw new ArgumentNullException("array");
|
||||
if (index < 0)
|
||||
throw new ArgumentOutOfRangeException("index", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNum));
|
||||
for (DictionaryNode node = list.head; node != null; node = node.next) {
|
||||
array.SetValue(isKeys ? node.key : node.value, index);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
int ICollection.Count {
|
||||
get {
|
||||
int count = 0;
|
||||
for (DictionaryNode node = list.head; node != null; node = node.next) {
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
bool ICollection.IsSynchronized {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
object ICollection.SyncRoot {
|
||||
get {
|
||||
return list.SyncRoot;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return new NodeKeyValueEnumerator(list, isKeys);
|
||||
}
|
||||
|
||||
|
||||
private class NodeKeyValueEnumerator: IEnumerator {
|
||||
ListDictionary list;
|
||||
DictionaryNode current;
|
||||
int version;
|
||||
bool isKeys;
|
||||
bool start;
|
||||
|
||||
public NodeKeyValueEnumerator(ListDictionary list, bool isKeys) {
|
||||
this.list = list;
|
||||
this.isKeys = isKeys;
|
||||
this.version = list.version;
|
||||
this.start = true;
|
||||
this.current = null;
|
||||
}
|
||||
|
||||
public object Current {
|
||||
get {
|
||||
if (current == null) {
|
||||
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumOpCantHappen));
|
||||
}
|
||||
return isKeys ? current.key : current.value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool MoveNext() {
|
||||
if (version != list.version) {
|
||||
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
|
||||
}
|
||||
if (start) {
|
||||
current = list.head;
|
||||
start = false;
|
||||
}
|
||||
else if (current != null) {
|
||||
current = current.next;
|
||||
}
|
||||
return (current != null);
|
||||
}
|
||||
|
||||
public void Reset() {
|
||||
if (version != list.version) {
|
||||
throw new InvalidOperationException(SR.GetString(SR.InvalidOperation_EnumFailedVersion));
|
||||
}
|
||||
start = true;
|
||||
current = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
private class DictionaryNode {
|
||||
public object key;
|
||||
public object value;
|
||||
public DictionaryNode next;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,485 @@
|
||||
// ==++==
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// ==--==
|
||||
//
|
||||
// <OWNER>[....]</OWNER>
|
||||
|
||||
using System.Security;
|
||||
using System.Collections;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Collections.Specialized;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace System.Runtime.InteropServices.WindowsRuntime
|
||||
{
|
||||
// Local definition of Windows.UI.Xaml.Interop.INotifyCollectionChangedEventArgs
|
||||
[ComImport]
|
||||
[Guid("4cf68d33-e3f2-4964-b85e-945b4f7e2f21")]
|
||||
[WindowsRuntimeImport]
|
||||
internal interface INotifyCollectionChangedEventArgs
|
||||
{
|
||||
NotifyCollectionChangedAction Action { get; }
|
||||
IList NewItems { get; }
|
||||
IList OldItems { get; }
|
||||
int NewStartingIndex { get; }
|
||||
int OldStartingIndex { get; }
|
||||
}
|
||||
|
||||
// Local definition of Windows.UI.Xaml.Data.IPropertyChangedEventArgs
|
||||
[ComImport]
|
||||
[Guid("4f33a9a0-5cf4-47a4-b16f-d7faaf17457e")]
|
||||
[WindowsRuntimeImport]
|
||||
internal interface IPropertyChangedEventArgs
|
||||
{
|
||||
string PropertyName { get; }
|
||||
}
|
||||
|
||||
// Local definition of Windows.UI.Xaml.Interop.INotifyCollectionChanged
|
||||
[ComImport]
|
||||
[Guid("28b167d5-1a31-465b-9b25-d5c3ae686c40")]
|
||||
[WindowsRuntimeImport]
|
||||
internal interface INotifyCollectionChanged_WinRT
|
||||
{
|
||||
EventRegistrationToken add_CollectionChanged(NotifyCollectionChangedEventHandler value);
|
||||
void remove_CollectionChanged(EventRegistrationToken token);
|
||||
}
|
||||
|
||||
// Local definition of Windows.UI.Xaml.Data.INotifyPropertyChanged
|
||||
[ComImport]
|
||||
[Guid("cf75d69c-f2f4-486b-b302-bb4c09baebfa")]
|
||||
[WindowsRuntimeImport]
|
||||
internal interface INotifyPropertyChanged_WinRT
|
||||
{
|
||||
EventRegistrationToken add_PropertyChanged(PropertyChangedEventHandler value);
|
||||
void remove_PropertyChanged(EventRegistrationToken token);
|
||||
}
|
||||
|
||||
// Local definition of Windows.UI.Xaml.Input.ICommand
|
||||
[ComImport]
|
||||
[Guid("e5af3542-ca67-4081-995b-709dd13792df")]
|
||||
[WindowsRuntimeImport]
|
||||
internal interface ICommand_WinRT
|
||||
{
|
||||
EventRegistrationToken add_CanExecuteChanged(EventHandler<object> value);
|
||||
void remove_CanExecuteChanged(EventRegistrationToken token);
|
||||
bool CanExecute(object parameter);
|
||||
void Execute(object parameter);
|
||||
}
|
||||
|
||||
// Local definition of Windows.UI.Xaml.Interop.NotifyCollectionChangedEventHandler
|
||||
[Guid("ca10b37c-f382-4591-8557-5e24965279b0")]
|
||||
[WindowsRuntimeImport]
|
||||
internal delegate void NotifyCollectionChangedEventHandler_WinRT(object sender, NotifyCollectionChangedEventArgs e);
|
||||
|
||||
// Local definition of Windows.UI.Xaml.Data.PropertyChangedEventHandler
|
||||
[Guid("50f19c16-0a22-4d8e-a089-1ea9951657d2")]
|
||||
[WindowsRuntimeImport]
|
||||
internal delegate void PropertyChangedEventHandler_WinRT(object sender, PropertyChangedEventArgs e);
|
||||
|
||||
internal static class NotifyCollectionChangedEventArgsMarshaler
|
||||
{
|
||||
// Extracts properties from a managed NotifyCollectionChangedEventArgs and passes them to
|
||||
// a VM-implemented helper that creates a WinRT NotifyCollectionChangedEventArgs instance.
|
||||
// This method is called from IL stubs and needs to have its token stabilized.
|
||||
[SecurityCritical]
|
||||
static internal IntPtr ConvertToNative(NotifyCollectionChangedEventArgs managedArgs)
|
||||
{
|
||||
if (managedArgs == null)
|
||||
return IntPtr.Zero;
|
||||
|
||||
return System.StubHelpers.EventArgsMarshaler.CreateNativeNCCEventArgsInstance(
|
||||
(int)managedArgs.Action,
|
||||
managedArgs.NewItems,
|
||||
managedArgs.OldItems,
|
||||
managedArgs.NewStartingIndex,
|
||||
managedArgs.OldStartingIndex);
|
||||
}
|
||||
|
||||
// Extracts properties from a WinRT NotifyCollectionChangedEventArgs and creates a new
|
||||
// managed NotifyCollectionChangedEventArgs instance.
|
||||
// This method is called from IL stubs and needs to have its token stabilized.
|
||||
[SecurityCritical]
|
||||
static internal NotifyCollectionChangedEventArgs ConvertToManaged(IntPtr nativeArgsIP)
|
||||
{
|
||||
if (nativeArgsIP == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
object obj = System.StubHelpers.InterfaceMarshaler.ConvertToManagedWithoutUnboxing(nativeArgsIP);
|
||||
INotifyCollectionChangedEventArgs nativeArgs = (INotifyCollectionChangedEventArgs)obj;
|
||||
|
||||
return new NotifyCollectionChangedEventArgs(
|
||||
nativeArgs.Action,
|
||||
nativeArgs.NewItems,
|
||||
nativeArgs.OldItems,
|
||||
nativeArgs.NewStartingIndex,
|
||||
nativeArgs.OldStartingIndex);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class PropertyChangedEventArgsMarshaler
|
||||
{
|
||||
// Extracts PropertyName from a managed PropertyChangedEventArgs and passes them to
|
||||
// a VM-implemented helper that creates a WinRT PropertyChangedEventArgs instance.
|
||||
// This method is called from IL stubs and needs to have its token stabilized.
|
||||
[SecurityCritical]
|
||||
static internal IntPtr ConvertToNative(PropertyChangedEventArgs managedArgs)
|
||||
{
|
||||
if (managedArgs == null)
|
||||
return IntPtr.Zero;
|
||||
|
||||
return System.StubHelpers.EventArgsMarshaler.CreateNativePCEventArgsInstance(managedArgs.PropertyName);
|
||||
}
|
||||
|
||||
// Extracts properties from a WinRT PropertyChangedEventArgs and creates a new
|
||||
// managed PropertyChangedEventArgs instance.
|
||||
// This method is called from IL stubs and needs to have its token stabilized.
|
||||
[SecurityCritical]
|
||||
static internal PropertyChangedEventArgs ConvertToManaged(IntPtr nativeArgsIP)
|
||||
{
|
||||
if (nativeArgsIP == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
object obj = System.StubHelpers.InterfaceMarshaler.ConvertToManagedWithoutUnboxing(nativeArgsIP);
|
||||
IPropertyChangedEventArgs nativeArgs = (IPropertyChangedEventArgs)obj;
|
||||
|
||||
return new PropertyChangedEventArgs(nativeArgs.PropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a set of stub methods implementing the support for the managed INotifyCollectionChanged
|
||||
// interface on WinRT objects that support the WinRT INotifyCollectionChanged. Used by the interop
|
||||
// mashaling infrastructure.
|
||||
internal sealed class NotifyCollectionChangedToManagedAdapter
|
||||
{
|
||||
private NotifyCollectionChangedToManagedAdapter()
|
||||
{
|
||||
Contract.Assert(false, "This class is never instantiated");
|
||||
}
|
||||
|
||||
internal event NotifyCollectionChangedEventHandler CollectionChanged
|
||||
{
|
||||
// void CollectionChanged.add(NotifyCollectionChangedEventHandler)
|
||||
[SecurityCritical]
|
||||
add
|
||||
{
|
||||
INotifyCollectionChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyCollectionChanged_WinRT>(this);
|
||||
|
||||
// call the WinRT eventing support in mscorlib to subscribe the event
|
||||
Func<NotifyCollectionChangedEventHandler, EventRegistrationToken> addMethod =
|
||||
new Func<NotifyCollectionChangedEventHandler, EventRegistrationToken>(_this.add_CollectionChanged);
|
||||
Action<EventRegistrationToken> removeMethod =
|
||||
new Action<EventRegistrationToken>(_this.remove_CollectionChanged);
|
||||
|
||||
WindowsRuntimeMarshal.AddEventHandler<NotifyCollectionChangedEventHandler>(addMethod, removeMethod, value);
|
||||
}
|
||||
|
||||
// void CollectionChanged.remove(NotifyCollectionChangedEventHandler)
|
||||
[SecurityCritical]
|
||||
remove
|
||||
{
|
||||
INotifyCollectionChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyCollectionChanged_WinRT>(this);
|
||||
|
||||
// call the WinRT eventing support in mscorlib to unsubscribe the event
|
||||
Action<EventRegistrationToken> removeMethod =
|
||||
new Action<EventRegistrationToken>(_this.remove_CollectionChanged);
|
||||
|
||||
WindowsRuntimeMarshal.RemoveEventHandler<NotifyCollectionChangedEventHandler>(removeMethod, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is a set of stub methods implementing the support for the WinRT INotifyCollectionChanged
|
||||
// interface on managed objects that support the managed INotifyCollectionChanged. Used by the interop
|
||||
// mashaling infrastructure.
|
||||
internal sealed class NotifyCollectionChangedToWinRTAdapter
|
||||
{
|
||||
private NotifyCollectionChangedToWinRTAdapter()
|
||||
{
|
||||
Contract.Assert(false, "This class is never instantiated");
|
||||
}
|
||||
|
||||
// An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
|
||||
// Since here the class can be an arbitrary implementation of INotifyCollectionChanged, we have to keep the EventRegistrationTokenTable's
|
||||
// separately, associated with the implementations using ConditionalWeakTable.
|
||||
private static ConditionalWeakTable<INotifyCollectionChanged, EventRegistrationTokenTable<NotifyCollectionChangedEventHandler>> m_weakTable =
|
||||
new ConditionalWeakTable<INotifyCollectionChanged, EventRegistrationTokenTable<NotifyCollectionChangedEventHandler>>();
|
||||
|
||||
// EventRegistrationToken CollectionChanged.add(NotifyCollectionChangedEventHandler value)
|
||||
[SecurityCritical]
|
||||
internal EventRegistrationToken add_CollectionChanged(NotifyCollectionChangedEventHandler value)
|
||||
{
|
||||
INotifyCollectionChanged _this = JitHelpers.UnsafeCast<INotifyCollectionChanged>(this);
|
||||
EventRegistrationTokenTable<NotifyCollectionChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
|
||||
|
||||
EventRegistrationToken token = table.AddEventHandler(value);
|
||||
_this.CollectionChanged += value;
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
// void CollectionChanged.remove(EventRegistrationToken token)
|
||||
[SecurityCritical]
|
||||
internal void remove_CollectionChanged(EventRegistrationToken token)
|
||||
{
|
||||
INotifyCollectionChanged _this = JitHelpers.UnsafeCast<INotifyCollectionChanged>(this);
|
||||
EventRegistrationTokenTable<NotifyCollectionChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
|
||||
|
||||
NotifyCollectionChangedEventHandler handler = table.ExtractHandler(token);
|
||||
if (handler != null)
|
||||
{
|
||||
_this.CollectionChanged -= handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is a set of stub methods implementing the support for the managed INotifyPropertyChanged
|
||||
// interface on WinRT objects that support the WinRT INotifyPropertyChanged. Used by the interop
|
||||
// mashaling infrastructure.
|
||||
internal sealed class NotifyPropertyChangedToManagedAdapter
|
||||
{
|
||||
private NotifyPropertyChangedToManagedAdapter()
|
||||
{
|
||||
Contract.Assert(false, "This class is never instantiated");
|
||||
}
|
||||
|
||||
internal event PropertyChangedEventHandler PropertyChanged
|
||||
{
|
||||
// void PropertyChanged.add(PropertyChangedEventHandler)
|
||||
[SecurityCritical]
|
||||
add
|
||||
{
|
||||
INotifyPropertyChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyPropertyChanged_WinRT>(this);
|
||||
|
||||
// call the WinRT eventing support in mscorlib to subscribe the event
|
||||
Func<PropertyChangedEventHandler, EventRegistrationToken> addMethod =
|
||||
new Func<PropertyChangedEventHandler, EventRegistrationToken>(_this.add_PropertyChanged);
|
||||
Action<EventRegistrationToken> removeMethod =
|
||||
new Action<EventRegistrationToken>(_this.remove_PropertyChanged);
|
||||
|
||||
WindowsRuntimeMarshal.AddEventHandler<PropertyChangedEventHandler>(addMethod, removeMethod, value);
|
||||
}
|
||||
|
||||
// void PropertyChanged.remove(PropertyChangedEventHandler)
|
||||
[SecurityCritical]
|
||||
remove
|
||||
{
|
||||
INotifyPropertyChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyPropertyChanged_WinRT>(this);
|
||||
|
||||
// call the WinRT eventing support in mscorlib to unsubscribe the event
|
||||
Action<EventRegistrationToken> removeMethod =
|
||||
new Action<EventRegistrationToken>(_this.remove_PropertyChanged);
|
||||
|
||||
WindowsRuntimeMarshal.RemoveEventHandler<PropertyChangedEventHandler>(removeMethod, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is a set of stub methods implementing the support for the WinRT INotifyPropertyChanged
|
||||
// interface on managed objects that support the managed INotifyPropertyChanged. Used by the interop
|
||||
// mashaling infrastructure.
|
||||
internal sealed class NotifyPropertyChangedToWinRTAdapter
|
||||
{
|
||||
private NotifyPropertyChangedToWinRTAdapter()
|
||||
{
|
||||
Contract.Assert(false, "This class is never instantiated");
|
||||
}
|
||||
|
||||
// An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
|
||||
// Since here the class can be an arbitrary implementation of INotifyCollectionChanged, we have to keep the EventRegistrationTokenTable's
|
||||
// separately, associated with the implementations using ConditionalWeakTable.
|
||||
private static ConditionalWeakTable<INotifyPropertyChanged, EventRegistrationTokenTable<PropertyChangedEventHandler>> m_weakTable =
|
||||
new ConditionalWeakTable<INotifyPropertyChanged, EventRegistrationTokenTable<PropertyChangedEventHandler>>();
|
||||
|
||||
// EventRegistrationToken PropertyChanged.add(PropertyChangedEventHandler value)
|
||||
[SecurityCritical]
|
||||
internal EventRegistrationToken add_PropertyChanged(PropertyChangedEventHandler value)
|
||||
{
|
||||
INotifyPropertyChanged _this = JitHelpers.UnsafeCast<INotifyPropertyChanged>(this);
|
||||
EventRegistrationTokenTable<PropertyChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
|
||||
|
||||
EventRegistrationToken token = table.AddEventHandler(value);
|
||||
_this.PropertyChanged += value;
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
// void PropertyChanged.remove(EventRegistrationToken token)
|
||||
[SecurityCritical]
|
||||
internal void remove_PropertyChanged(EventRegistrationToken token)
|
||||
{
|
||||
INotifyPropertyChanged _this = JitHelpers.UnsafeCast<INotifyPropertyChanged>(this);
|
||||
EventRegistrationTokenTable<PropertyChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
|
||||
|
||||
PropertyChangedEventHandler handler = table.ExtractHandler(token);
|
||||
if (handler != null)
|
||||
{
|
||||
_this.PropertyChanged -= handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is a set of stub methods implementing the support for the managed ICommand
|
||||
// interface on WinRT objects that support the WinRT ICommand_WinRT.
|
||||
// Used by the interop mashaling infrastructure.
|
||||
// Instances of this are really RCWs of ICommand_WinRT (not ICommandToManagedAdapter or any ICommand).
|
||||
[SecurityCritical]
|
||||
internal sealed class ICommandToManagedAdapter /*: System.Windows.Input.ICommand*/
|
||||
{
|
||||
private static ConditionalWeakTable<EventHandler, EventHandler<object>> m_weakTable =
|
||||
new ConditionalWeakTable<EventHandler, EventHandler<object>>();
|
||||
|
||||
private ICommandToManagedAdapter()
|
||||
{
|
||||
Contract.Assert(false, "This class is never instantiated");
|
||||
}
|
||||
|
||||
private event EventHandler CanExecuteChanged
|
||||
{
|
||||
// void CanExecuteChanged.add(EventHandler)
|
||||
add
|
||||
{
|
||||
ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
|
||||
|
||||
// call the WinRT eventing support in mscorlib to subscribe the event
|
||||
Func<EventHandler<object>, EventRegistrationToken> addMethod =
|
||||
new Func<EventHandler<object>, EventRegistrationToken>(_this.add_CanExecuteChanged);
|
||||
Action<EventRegistrationToken> removeMethod =
|
||||
new Action<EventRegistrationToken>(_this.remove_CanExecuteChanged);
|
||||
|
||||
// value is of type System.EventHandler, but ICommand_WinRT (and thus WindowsRuntimeMarshal.AddEventHandler)
|
||||
// expects an instance of EventHandler<object>. So we get/create a wrapper of value here.
|
||||
EventHandler<object> handler_WinRT = m_weakTable.GetValue(value, ICommandAdapterHelpers.CreateWrapperHandler);
|
||||
WindowsRuntimeMarshal.AddEventHandler<EventHandler<object>>(addMethod, removeMethod, handler_WinRT);
|
||||
}
|
||||
|
||||
// void CanExecuteChanged.remove(EventHandler)
|
||||
remove
|
||||
{
|
||||
ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
|
||||
|
||||
// call the WinRT eventing support in mscorlib to unsubscribe the event
|
||||
Action<EventRegistrationToken> removeMethod =
|
||||
new Action<EventRegistrationToken>(_this.remove_CanExecuteChanged);
|
||||
|
||||
// value is of type System.EventHandler, but ICommand_WinRT (and thus WindowsRuntimeMarshal.RemoveEventHandler)
|
||||
// expects an instance of EventHandler<object>. So we get/create a wrapper of value here.
|
||||
|
||||
// Also we do a value check rather than an instance check to ensure that different instances of the same delegates are treated equal.
|
||||
EventHandler<object> handler_WinRT = ICommandAdapterHelpers.GetValueFromEquivalentKey(m_weakTable , value, ICommandAdapterHelpers.CreateWrapperHandler);
|
||||
WindowsRuntimeMarshal.RemoveEventHandler<EventHandler<object>>(removeMethod, handler_WinRT);
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanExecute(object parameter)
|
||||
{
|
||||
ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
|
||||
return _this.CanExecute(parameter);
|
||||
}
|
||||
|
||||
private void Execute(object parameter)
|
||||
{
|
||||
ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
|
||||
_this.Execute(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
// This is a set of stub methods implementing the support for the WinRT ICommand_WinRT
|
||||
// interface on managed objects that support the managed ICommand interface.
|
||||
// Used by the interop mashaling infrastructure.
|
||||
// Instances of this are really CCWs of ICommand (not ICommandToWinRTAdapter or any ICommand_WinRT).
|
||||
[SecurityCritical]
|
||||
internal sealed class ICommandToWinRTAdapter /*: ICommand_WinRT*/
|
||||
{
|
||||
private ICommandToWinRTAdapter()
|
||||
{
|
||||
Contract.Assert(false, "This class is never instantiated");
|
||||
}
|
||||
|
||||
// An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
|
||||
// Since here the class can be an arbitrary implementation of ICommand, we have to keep the EventRegistrationTokenTable's
|
||||
// separately, associated with the implementations using ConditionalWeakTable.
|
||||
private static ConditionalWeakTable<ICommand, EventRegistrationTokenTable<EventHandler>> m_weakTable =
|
||||
new ConditionalWeakTable<ICommand, EventRegistrationTokenTable<EventHandler>>();
|
||||
|
||||
// EventRegistrationToken PropertyChanged.add(EventHandler<object> value)
|
||||
private EventRegistrationToken add_CanExecuteChanged(EventHandler<object> value)
|
||||
{
|
||||
ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
|
||||
EventRegistrationTokenTable<EventHandler> table = m_weakTable.GetOrCreateValue(_this);
|
||||
|
||||
EventHandler handler = ICommandAdapterHelpers.CreateWrapperHandler(value);
|
||||
EventRegistrationToken token = table.AddEventHandler(handler);
|
||||
_this.CanExecuteChanged += handler;
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
// void PropertyChanged.remove(EventRegistrationToken token)
|
||||
private void remove_CanExecuteChanged(EventRegistrationToken token)
|
||||
{
|
||||
ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
|
||||
EventRegistrationTokenTable<EventHandler> table = m_weakTable.GetOrCreateValue(_this);
|
||||
|
||||
EventHandler handler = table.ExtractHandler(token);
|
||||
if (handler != null)
|
||||
{
|
||||
_this.CanExecuteChanged -= handler;
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanExecute(object parameter)
|
||||
{
|
||||
ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
|
||||
return _this.CanExecute(parameter);
|
||||
}
|
||||
|
||||
private void Execute(object parameter)
|
||||
{
|
||||
ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
|
||||
_this.Execute(parameter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// A couple of ICommand adapter helpers need to be transparent, and so are in their own type
|
||||
internal static class ICommandAdapterHelpers
|
||||
{
|
||||
internal static EventHandler<object> CreateWrapperHandler(EventHandler handler)
|
||||
{
|
||||
// Check whether it is a round-tripping case i.e. the sender is of the type eventArgs,
|
||||
// If so we use it else we pass EventArgs.Empty
|
||||
return (object sender, object e) =>
|
||||
{
|
||||
EventArgs eventArgs = e as EventArgs;
|
||||
handler(sender, (eventArgs == null ? System.EventArgs.Empty : eventArgs));
|
||||
};
|
||||
}
|
||||
|
||||
internal static EventHandler CreateWrapperHandler(EventHandler<object> handler)
|
||||
{
|
||||
return (object sender, EventArgs e) => handler(sender, e);
|
||||
}
|
||||
|
||||
internal static EventHandler<object> GetValueFromEquivalentKey(
|
||||
ConditionalWeakTable<EventHandler, EventHandler<object>> table,
|
||||
EventHandler key,
|
||||
ConditionalWeakTable<EventHandler, EventHandler<object>>.CreateValueCallback callback)
|
||||
{
|
||||
EventHandler<object> value;
|
||||
|
||||
// Find the key in the table using a value check rather than an instance check.
|
||||
EventHandler existingKey = table.FindEquivalentKeyUnsafe(key, out value);
|
||||
if (existingKey == null)
|
||||
{
|
||||
value = callback(key);
|
||||
table.Add(key, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,395 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="NameValueCollection.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Ordered String/String[] collection of name/value pairs with support for null key
|
||||
* Wraps NameObject collection
|
||||
*
|
||||
* Copyright (c) 2000 Microsoft Corporation
|
||||
*/
|
||||
|
||||
namespace System.Collections.Specialized {
|
||||
|
||||
using Microsoft.Win32;
|
||||
using System.Collections;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Globalization;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Represents a sorted collection of associated <see cref='System.String' qualify='true'/> keys and <see cref='System.String' qualify='true'/> values that
|
||||
/// can be accessed either with the hash code of the key or with the index.</para>
|
||||
/// </devdoc>
|
||||
[Serializable()]
|
||||
public class NameValueCollection : NameObjectCollectionBase {
|
||||
|
||||
private String[] _all;
|
||||
private String[] _allKeys;
|
||||
|
||||
//
|
||||
// Constructors
|
||||
//
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Creates an empty <see cref='System.Collections.Specialized.NameValueCollection'/> with the default initial capacity
|
||||
/// and using the default case-insensitive hash code provider and the default
|
||||
/// case-insensitive comparer.</para>
|
||||
/// </devdoc>
|
||||
public NameValueCollection() : base() {
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Copies the entries from the specified <see cref='System.Collections.Specialized.NameValueCollection'/> to a new <see cref='System.Collections.Specialized.NameValueCollection'/> with the same initial capacity as
|
||||
/// the number of entries copied and using the default case-insensitive hash code
|
||||
/// provider and the default case-insensitive comparer.</para>
|
||||
/// </devdoc>
|
||||
public NameValueCollection(NameValueCollection col)
|
||||
: base( col != null? col.Comparer : null) {
|
||||
Add(col);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Creates an empty <see cref='System.Collections.Specialized.NameValueCollection'/> with the default initial capacity
|
||||
/// and using the specified case-insensitive hash code provider and the specified
|
||||
/// case-insensitive comparer.</para>
|
||||
/// </devdoc>
|
||||
#pragma warning disable 618
|
||||
[Obsolete("Please use NameValueCollection(IEqualityComparer) instead.")]
|
||||
public NameValueCollection(IHashCodeProvider hashProvider, IComparer comparer)
|
||||
: base(hashProvider, comparer) {
|
||||
}
|
||||
#pragma warning restore 618
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Creates an empty <see cref='System.Collections.Specialized.NameValueCollection'/> with
|
||||
/// the specified initial capacity and using the default case-insensitive hash code
|
||||
/// provider and the default case-insensitive comparer.</para>
|
||||
/// </devdoc>
|
||||
public NameValueCollection(int capacity) : base(capacity) {
|
||||
}
|
||||
|
||||
public NameValueCollection(IEqualityComparer equalityComparer) : base( equalityComparer) {
|
||||
}
|
||||
|
||||
public NameValueCollection(Int32 capacity, IEqualityComparer equalityComparer)
|
||||
: base(capacity, equalityComparer) {
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Copies the entries from the specified <see cref='System.Collections.Specialized.NameValueCollection'/> to a new <see cref='System.Collections.Specialized.NameValueCollection'/> with the specified initial capacity or the
|
||||
/// same initial capacity as the number of entries copied, whichever is greater, and
|
||||
/// using the default case-insensitive hash code provider and the default
|
||||
/// case-insensitive comparer.</para>
|
||||
/// </devdoc>
|
||||
public NameValueCollection(int capacity, NameValueCollection col)
|
||||
: base(capacity, (col != null ? col.Comparer : null)) {
|
||||
if( col == null) {
|
||||
throw new ArgumentNullException("col");
|
||||
}
|
||||
|
||||
this.Comparer = col.Comparer;
|
||||
Add(col);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Creates an empty <see cref='System.Collections.Specialized.NameValueCollection'/> with the specified initial capacity and
|
||||
/// using the specified case-insensitive hash code provider and the specified
|
||||
/// case-insensitive comparer.</para>
|
||||
/// </devdoc>
|
||||
#pragma warning disable 618
|
||||
[Obsolete("Please use NameValueCollection(Int32, IEqualityComparer) instead.")]
|
||||
public NameValueCollection(int capacity, IHashCodeProvider hashProvider, IComparer comparer)
|
||||
: base(capacity, hashProvider, comparer) {
|
||||
}
|
||||
#pragma warning restore 618
|
||||
|
||||
// Allow internal extenders to avoid creating the hashtable/arraylist.
|
||||
internal NameValueCollection(DBNull dummy) : base(dummy)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Serialization support
|
||||
//
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
protected NameValueCollection(SerializationInfo info, StreamingContext context) : base(info, context) {
|
||||
}
|
||||
|
||||
//
|
||||
// Helper methods
|
||||
//
|
||||
|
||||
/// <devdoc>
|
||||
/// <para> Resets the cached arrays of the collection to <see langword='null'/>.</para>
|
||||
/// </devdoc>
|
||||
protected void InvalidateCachedArrays() {
|
||||
_all = null;
|
||||
_allKeys = null;
|
||||
}
|
||||
|
||||
private static String GetAsOneString(ArrayList list) {
|
||||
int n = (list != null) ? list.Count : 0;
|
||||
|
||||
if (n == 1) {
|
||||
return (String)list[0];
|
||||
}
|
||||
else if (n > 1) {
|
||||
StringBuilder s = new StringBuilder((String)list[0]);
|
||||
|
||||
for (int i = 1; i < n; i++) {
|
||||
s.Append(',');
|
||||
s.Append((String)list[i]);
|
||||
}
|
||||
|
||||
return s.ToString();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String[] GetAsStringArray(ArrayList list)
|
||||
{
|
||||
int n = (list != null) ? list.Count : 0;
|
||||
if (n == 0)
|
||||
return null;
|
||||
|
||||
String [] array = new String[n];
|
||||
list.CopyTo(0, array, 0, n);
|
||||
return array;
|
||||
}
|
||||
|
||||
//
|
||||
// Misc public APIs
|
||||
//
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Copies the entries in the specified <see cref='System.Collections.Specialized.NameValueCollection'/> to the current <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
|
||||
/// </devdoc>
|
||||
public void Add(NameValueCollection c) {
|
||||
if( c == null) {
|
||||
throw new ArgumentNullException("c");
|
||||
}
|
||||
|
||||
InvalidateCachedArrays();
|
||||
|
||||
int n = c.Count;
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
String key = c.GetKey(i);
|
||||
String[] values = c.GetValues(i);
|
||||
|
||||
if (values != null) {
|
||||
for (int j = 0; j < values.Length; j++)
|
||||
Add(key, values[j]);
|
||||
}
|
||||
else {
|
||||
Add(key, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Invalidates the cached arrays and removes all entries
|
||||
/// from the <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
|
||||
/// </devdoc>
|
||||
public virtual void Clear() {
|
||||
if (IsReadOnly)
|
||||
throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
|
||||
|
||||
InvalidateCachedArrays();
|
||||
BaseClear();
|
||||
}
|
||||
|
||||
public void CopyTo(Array dest, int index) {
|
||||
if (dest==null) {
|
||||
throw new ArgumentNullException("dest");
|
||||
}
|
||||
|
||||
if (dest.Rank != 1) {
|
||||
throw new ArgumentException(SR.GetString(SR.Arg_MultiRank));
|
||||
}
|
||||
|
||||
if (index < 0) {
|
||||
throw new ArgumentOutOfRangeException("index",SR.GetString(SR.IndexOutOfRange, index.ToString(CultureInfo.CurrentCulture)) );
|
||||
}
|
||||
|
||||
if (dest.Length - index < Count) {
|
||||
throw new ArgumentException(SR.GetString(SR.Arg_InsufficientSpace));
|
||||
}
|
||||
|
||||
int n = Count;
|
||||
if (_all == null) {
|
||||
String[] all = new String[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
all[i] = Get(i);
|
||||
dest.SetValue( all[i], i + index);
|
||||
}
|
||||
_all = all; // wait until end of loop to set _all reference in case Get throws
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < n; i++) {
|
||||
dest.SetValue( _all[i], i + index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets a value indicating whether the <see cref='System.Collections.Specialized.NameValueCollection'/> contains entries whose keys are not <see langword='null'/>.</para>
|
||||
/// </devdoc>
|
||||
public bool HasKeys() {
|
||||
return InternalHasKeys();
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Allows derived classes to alter HasKeys().</para>
|
||||
/// </devdoc>
|
||||
internal virtual bool InternalHasKeys()
|
||||
{
|
||||
return BaseHasKeys();
|
||||
}
|
||||
|
||||
//
|
||||
// Access by name
|
||||
//
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Adds an entry with the specified name and value into the
|
||||
/// <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
|
||||
/// </devdoc>
|
||||
public virtual void Add(String name, String value) {
|
||||
if (IsReadOnly)
|
||||
throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
|
||||
|
||||
InvalidateCachedArrays();
|
||||
|
||||
ArrayList values = (ArrayList)BaseGet(name);
|
||||
|
||||
if (values == null) {
|
||||
// new key - add new key with single value
|
||||
values = new ArrayList(1);
|
||||
if (value != null)
|
||||
values.Add(value);
|
||||
BaseAdd(name, values);
|
||||
}
|
||||
else {
|
||||
// old key -- append value to the list of values
|
||||
if (value != null)
|
||||
values.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para> Gets the values associated with the specified key from the <see cref='System.Collections.Specialized.NameValueCollection'/> combined into one comma-separated list.</para>
|
||||
/// </devdoc>
|
||||
public virtual String Get(String name) {
|
||||
ArrayList values = (ArrayList)BaseGet(name);
|
||||
return GetAsOneString(values);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets the values associated with the specified key from the <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
|
||||
/// </devdoc>
|
||||
public virtual String[] GetValues(String name) {
|
||||
ArrayList values = (ArrayList)BaseGet(name);
|
||||
return GetAsStringArray(values);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Adds a value to an entry in the <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
|
||||
/// </devdoc>
|
||||
public virtual void Set(String name, String value) {
|
||||
if (IsReadOnly)
|
||||
throw new NotSupportedException(SR.GetString(SR.CollectionReadOnly));
|
||||
|
||||
InvalidateCachedArrays();
|
||||
|
||||
ArrayList values = new ArrayList(1);
|
||||
values.Add(value);
|
||||
BaseSet(name, values);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Removes the entries with the specified key from the <see cref='System.Collections.Specialized.NameObjectCollectionBase'/> instance.</para>
|
||||
/// </devdoc>
|
||||
public virtual void Remove(String name) {
|
||||
InvalidateCachedArrays();
|
||||
BaseRemove(name);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para> Represents the entry with the specified key in the
|
||||
/// <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
|
||||
/// </devdoc>
|
||||
public String this[String name] {
|
||||
get {
|
||||
return Get(name);
|
||||
}
|
||||
|
||||
set {
|
||||
Set(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Indexed access
|
||||
//
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Gets the values at the specified index of the <see cref='System.Collections.Specialized.NameValueCollection'/> combined into one
|
||||
/// comma-separated list.</para>
|
||||
/// </devdoc>
|
||||
public virtual String Get(int index) {
|
||||
ArrayList values = (ArrayList)BaseGet(index);
|
||||
return GetAsOneString(values);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para> Gets the values at the specified index of the <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
|
||||
/// </devdoc>
|
||||
public virtual String[] GetValues(int index) {
|
||||
ArrayList values = (ArrayList)BaseGet(index);
|
||||
return GetAsStringArray(values);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets the key at the specified index of the <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
|
||||
/// </devdoc>
|
||||
public virtual String GetKey(int index) {
|
||||
return BaseGetKey(index);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Represents the entry at the specified index of the <see cref='System.Collections.Specialized.NameValueCollection'/>.</para>
|
||||
/// </devdoc>
|
||||
public String this[int index] {
|
||||
get {
|
||||
return Get(index);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Access to keys and values as arrays
|
||||
//
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets all the keys in the <see cref='System.Collections.Specialized.NameValueCollection'/>. </para>
|
||||
/// </devdoc>
|
||||
public virtual String[] AllKeys {
|
||||
get {
|
||||
if (_allKeys == null)
|
||||
_allKeys = BaseGetAllKeys();
|
||||
return _allKeys;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// <copyright file="NotifyCollectionChangedEventArgs.cs" company="Microsoft">
|
||||
// Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//
|
||||
// Description: NotifyCollectionChanged event arguments
|
||||
//
|
||||
// Specs: http://avalon/connecteddata/Specs/INotifyCollectionChanged.mht
|
||||
//
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Collections.Specialized
|
||||
{
|
||||
/// <summary>
|
||||
/// This enum describes the action that caused a CollectionChanged event.
|
||||
/// </summary>
|
||||
#if !MOBILE
|
||||
[TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
|
||||
#endif
|
||||
public enum NotifyCollectionChangedAction
|
||||
{
|
||||
/// <summary> One or more items were added to the collection. </summary>
|
||||
Add,
|
||||
/// <summary> One or more items were removed from the collection. </summary>
|
||||
Remove,
|
||||
/// <summary> One or more items were replaced in the collection. </summary>
|
||||
Replace,
|
||||
/// <summary> One or more items were moved within the collection. </summary>
|
||||
Move,
|
||||
/// <summary> The contents of the collection changed dramatically. </summary>
|
||||
Reset,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Arguments for the CollectionChanged event.
|
||||
/// A collection that supports INotifyCollectionChangedThis raises this event
|
||||
/// whenever an item is added or removed, or when the contents of the collection
|
||||
/// changes dramatically.
|
||||
/// </summary>
|
||||
#if !MOBILE
|
||||
[TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
|
||||
#endif
|
||||
public class NotifyCollectionChangedEventArgs : EventArgs
|
||||
{
|
||||
//------------------------------------------------------
|
||||
//
|
||||
// Constructors
|
||||
//
|
||||
//------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Construct a NotifyCollectionChangedEventArgs that describes a reset change.
|
||||
/// </summary>
|
||||
/// <param name="action">The action that caused the event (must be Reset).</param>
|
||||
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action)
|
||||
{
|
||||
if (action != NotifyCollectionChangedAction.Reset)
|
||||
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Reset), "action");
|
||||
|
||||
InitializeAdd(action, null, -1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a NotifyCollectionChangedEventArgs that describes a one-item change.
|
||||
/// </summary>
|
||||
/// <param name="action">The action that caused the event; can only be Reset, Add or Remove action.</param>
|
||||
/// <param name="changedItem">The item affected by the change.</param>
|
||||
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem)
|
||||
{
|
||||
if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
|
||||
&& (action != NotifyCollectionChangedAction.Reset))
|
||||
throw new ArgumentException(SR.GetString(SR.MustBeResetAddOrRemoveActionForCtor), "action");
|
||||
|
||||
if (action == NotifyCollectionChangedAction.Reset)
|
||||
{
|
||||
if (changedItem != null)
|
||||
throw new ArgumentException(SR.GetString(SR.ResetActionRequiresNullItem), "action");
|
||||
|
||||
InitializeAdd(action, null, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitializeAddOrRemove(action, new object[]{changedItem}, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a NotifyCollectionChangedEventArgs that describes a one-item change.
|
||||
/// </summary>
|
||||
/// <param name="action">The action that caused the event.</param>
|
||||
/// <param name="changedItem">The item affected by the change.</param>
|
||||
/// <param name="index">The index where the change occurred.</param>
|
||||
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index)
|
||||
{
|
||||
if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
|
||||
&& (action != NotifyCollectionChangedAction.Reset))
|
||||
throw new ArgumentException(SR.GetString(SR.MustBeResetAddOrRemoveActionForCtor), "action");
|
||||
|
||||
if (action == NotifyCollectionChangedAction.Reset)
|
||||
{
|
||||
if (changedItem != null)
|
||||
throw new ArgumentException(SR.GetString(SR.ResetActionRequiresNullItem), "action");
|
||||
if (index != -1)
|
||||
throw new ArgumentException(SR.GetString(SR.ResetActionRequiresIndexMinus1), "action");
|
||||
|
||||
InitializeAdd(action, null, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
InitializeAddOrRemove(action, new object[]{changedItem}, index);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a NotifyCollectionChangedEventArgs that describes a multi-item change.
|
||||
/// </summary>
|
||||
/// <param name="action">The action that caused the event.</param>
|
||||
/// <param name="changedItems">The items affected by the change.</param>
|
||||
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems)
|
||||
{
|
||||
if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
|
||||
&& (action != NotifyCollectionChangedAction.Reset))
|
||||
throw new ArgumentException(SR.GetString(SR.MustBeResetAddOrRemoveActionForCtor), "action");
|
||||
|
||||
if (action == NotifyCollectionChangedAction.Reset)
|
||||
{
|
||||
if (changedItems != null)
|
||||
throw new ArgumentException(SR.GetString(SR.ResetActionRequiresNullItem), "action");
|
||||
|
||||
InitializeAdd(action, null, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (changedItems == null)
|
||||
throw new ArgumentNullException("changedItems");
|
||||
|
||||
InitializeAddOrRemove(action, changedItems, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a NotifyCollectionChangedEventArgs that describes a multi-item change (or a reset).
|
||||
/// </summary>
|
||||
/// <param name="action">The action that caused the event.</param>
|
||||
/// <param name="changedItems">The items affected by the change.</param>
|
||||
/// <param name="startingIndex">The index where the change occurred.</param>
|
||||
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
|
||||
{
|
||||
if ((action != NotifyCollectionChangedAction.Add) && (action != NotifyCollectionChangedAction.Remove)
|
||||
&& (action != NotifyCollectionChangedAction.Reset))
|
||||
throw new ArgumentException(SR.GetString(SR.MustBeResetAddOrRemoveActionForCtor), "action");
|
||||
|
||||
if (action == NotifyCollectionChangedAction.Reset)
|
||||
{
|
||||
if (changedItems != null)
|
||||
throw new ArgumentException(SR.GetString(SR.ResetActionRequiresNullItem), "action");
|
||||
if (startingIndex != -1)
|
||||
throw new ArgumentException(SR.GetString(SR.ResetActionRequiresIndexMinus1), "action");
|
||||
|
||||
InitializeAdd(action, null, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (changedItems == null)
|
||||
throw new ArgumentNullException("changedItems");
|
||||
if (startingIndex < -1)
|
||||
throw new ArgumentException(SR.GetString(SR.IndexCannotBeNegative), "startingIndex");
|
||||
|
||||
InitializeAddOrRemove(action, changedItems, startingIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a NotifyCollectionChangedEventArgs that describes a one-item Replace event.
|
||||
/// </summary>
|
||||
/// <param name="action">Can only be a Replace action.</param>
|
||||
/// <param name="newItem">The new item replacing the original item.</param>
|
||||
/// <param name="oldItem">The original item that is replaced.</param>
|
||||
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem)
|
||||
{
|
||||
if (action != NotifyCollectionChangedAction.Replace)
|
||||
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Replace), "action");
|
||||
|
||||
InitializeMoveOrReplace(action, new object[]{newItem}, new object[]{oldItem}, -1, -1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a NotifyCollectionChangedEventArgs that describes a one-item Replace event.
|
||||
/// </summary>
|
||||
/// <param name="action">Can only be a Replace action.</param>
|
||||
/// <param name="newItem">The new item replacing the original item.</param>
|
||||
/// <param name="oldItem">The original item that is replaced.</param>
|
||||
/// <param name="index">The index of the item being replaced.</param>
|
||||
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object newItem, object oldItem, int index)
|
||||
{
|
||||
if (action != NotifyCollectionChangedAction.Replace)
|
||||
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Replace), "action");
|
||||
|
||||
int oldStartingIndex = index;
|
||||
|
||||
#if FEATURE_LEGACYNETCF
|
||||
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
|
||||
{
|
||||
// Dev11 444113 quirk:
|
||||
// This is a "Replace" so the old and new index should both be set to the index passed in however
|
||||
// NetCF on Mango incorrectly leaves OldStartingIndex at -1 and Mango apps depend on this behavior.
|
||||
oldStartingIndex = -1;
|
||||
}
|
||||
#endif
|
||||
InitializeMoveOrReplace(action, new object[]{newItem}, new object[]{oldItem}, index, oldStartingIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Replace event.
|
||||
/// </summary>
|
||||
/// <param name="action">Can only be a Replace action.</param>
|
||||
/// <param name="newItems">The new items replacing the original items.</param>
|
||||
/// <param name="oldItems">The original items that are replaced.</param>
|
||||
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems)
|
||||
{
|
||||
if (action != NotifyCollectionChangedAction.Replace)
|
||||
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Replace), "action");
|
||||
if (newItems == null)
|
||||
throw new ArgumentNullException("newItems");
|
||||
if (oldItems == null)
|
||||
throw new ArgumentNullException("oldItems");
|
||||
|
||||
InitializeMoveOrReplace(action, newItems, oldItems, -1, -1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Replace event.
|
||||
/// </summary>
|
||||
/// <param name="action">Can only be a Replace action.</param>
|
||||
/// <param name="newItems">The new items replacing the original items.</param>
|
||||
/// <param name="oldItems">The original items that are replaced.</param>
|
||||
/// <param name="startingIndex">The starting index of the items being replaced.</param>
|
||||
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex)
|
||||
{
|
||||
if (action != NotifyCollectionChangedAction.Replace)
|
||||
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Replace), "action");
|
||||
if (newItems == null)
|
||||
throw new ArgumentNullException("newItems");
|
||||
if (oldItems == null)
|
||||
throw new ArgumentNullException("oldItems");
|
||||
|
||||
InitializeMoveOrReplace(action, newItems, oldItems, startingIndex, startingIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a NotifyCollectionChangedEventArgs that describes a one-item Move event.
|
||||
/// </summary>
|
||||
/// <param name="action">Can only be a Move action.</param>
|
||||
/// <param name="changedItem">The item affected by the change.</param>
|
||||
/// <param name="index">The new index for the changed item.</param>
|
||||
/// <param name="oldIndex">The old index for the changed item.</param>
|
||||
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, object changedItem, int index, int oldIndex)
|
||||
{
|
||||
if (action != NotifyCollectionChangedAction.Move)
|
||||
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Move), "action");
|
||||
if (index < 0)
|
||||
throw new ArgumentException(SR.GetString(SR.IndexCannotBeNegative), "index");
|
||||
|
||||
object[] changedItems= new object[] {changedItem};
|
||||
InitializeMoveOrReplace(action, changedItems, changedItems, index, oldIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a NotifyCollectionChangedEventArgs that describes a multi-item Move event.
|
||||
/// </summary>
|
||||
/// <param name="action">The action that caused the event.</param>
|
||||
/// <param name="changedItems">The items affected by the change.</param>
|
||||
/// <param name="index">The new index for the changed items.</param>
|
||||
/// <param name="oldIndex">The old index for the changed items.</param>
|
||||
public NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList changedItems, int index, int oldIndex)
|
||||
{
|
||||
if (action != NotifyCollectionChangedAction.Move)
|
||||
throw new ArgumentException(SR.GetString(SR.WrongActionForCtor, NotifyCollectionChangedAction.Move), "action");
|
||||
if (index < 0)
|
||||
throw new ArgumentException(SR.GetString(SR.IndexCannotBeNegative), "index");
|
||||
|
||||
InitializeMoveOrReplace(action, changedItems, changedItems, index, oldIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Construct a NotifyCollectionChangedEventArgs with given fields (no validation). Used by WinRT marshaling.
|
||||
/// </summary>
|
||||
internal NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int newIndex, int oldIndex)
|
||||
{
|
||||
_action = action;
|
||||
#if FEATURE_LEGACYNETCF
|
||||
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
|
||||
{
|
||||
_newItems = newItems;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
_newItems = (newItems == null) ? null : ArrayList.ReadOnly(newItems);
|
||||
}
|
||||
_oldItems = (oldItems == null) ? null : ArrayList.ReadOnly(oldItems);
|
||||
_newStartingIndex = newIndex;
|
||||
_oldStartingIndex = oldIndex;
|
||||
}
|
||||
|
||||
private void InitializeAddOrRemove(NotifyCollectionChangedAction action, IList changedItems, int startingIndex)
|
||||
{
|
||||
if (action == NotifyCollectionChangedAction.Add)
|
||||
InitializeAdd(action, changedItems, startingIndex);
|
||||
else if (action == NotifyCollectionChangedAction.Remove)
|
||||
InitializeRemove(action, changedItems, startingIndex);
|
||||
else
|
||||
Contract.Assert(false, String.Format("Unsupported action: {0}", action.ToString()));
|
||||
}
|
||||
|
||||
private void InitializeAdd(NotifyCollectionChangedAction action, IList newItems, int newStartingIndex)
|
||||
{
|
||||
_action = action;
|
||||
#if FEATURE_LEGACYNETCF
|
||||
if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
|
||||
{
|
||||
_newItems = newItems;
|
||||
}
|
||||
else
|
||||
#endif // !FEATURE_LEGACYNETCF
|
||||
{
|
||||
_newItems = (newItems == null) ? null : ArrayList.ReadOnly(newItems);
|
||||
}
|
||||
_newStartingIndex = newStartingIndex;
|
||||
}
|
||||
|
||||
private void InitializeRemove(NotifyCollectionChangedAction action, IList oldItems, int oldStartingIndex)
|
||||
{
|
||||
_action = action;
|
||||
_oldItems = (oldItems == null) ? null : ArrayList.ReadOnly(oldItems);
|
||||
_oldStartingIndex= oldStartingIndex;
|
||||
}
|
||||
|
||||
private void InitializeMoveOrReplace(NotifyCollectionChangedAction action, IList newItems, IList oldItems, int startingIndex, int oldStartingIndex)
|
||||
{
|
||||
InitializeAdd(action, newItems, startingIndex);
|
||||
InitializeRemove(action, oldItems, oldStartingIndex);
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
//
|
||||
// Public Properties
|
||||
//
|
||||
//------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// The action that caused the event.
|
||||
/// </summary>
|
||||
public NotifyCollectionChangedAction Action
|
||||
{
|
||||
get { return _action; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The items affected by the change.
|
||||
/// </summary>
|
||||
public IList NewItems
|
||||
{
|
||||
get { return _newItems; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The old items affected by the change (for Replace events).
|
||||
/// </summary>
|
||||
public IList OldItems
|
||||
{
|
||||
get { return _oldItems; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The index where the change occurred.
|
||||
/// </summary>
|
||||
public int NewStartingIndex
|
||||
{
|
||||
get { return _newStartingIndex; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The old index where the change occurred (for Move events).
|
||||
/// </summary>
|
||||
public int OldStartingIndex
|
||||
{
|
||||
get { return _oldStartingIndex; }
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
//
|
||||
// Private Fields
|
||||
//
|
||||
//------------------------------------------------------
|
||||
|
||||
private NotifyCollectionChangedAction _action;
|
||||
private IList _newItems, _oldItems;
|
||||
private int _newStartingIndex = -1;
|
||||
private int _oldStartingIndex = -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The delegate to use for handlers that receive the CollectionChanged event.
|
||||
/// </summary>
|
||||
#if !MOBILE
|
||||
[TypeForwardedFrom("WindowsBase, Version=3.0.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
|
||||
#endif
|
||||
public delegate void NotifyCollectionChangedEventHandler(object sender, NotifyCollectionChangedEventArgs e);
|
||||
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,246 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="StringCollection.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Collections.Specialized {
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Collections;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Represents a collection of strings.</para>
|
||||
/// </devdoc>
|
||||
[
|
||||
Serializable,
|
||||
]
|
||||
public class StringCollection : IList {
|
||||
private ArrayList data = new ArrayList();
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Represents the entry at the specified index of the <see cref='System.Collections.Specialized.StringCollection'/>.</para>
|
||||
/// </devdoc>
|
||||
public string this[int index] {
|
||||
get {
|
||||
return ((string)data[index]);
|
||||
}
|
||||
set {
|
||||
data[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets the number of strings in the
|
||||
/// <see cref='System.Collections.Specialized.StringCollection'/> .</para>
|
||||
/// </devdoc>
|
||||
public int Count {
|
||||
get {
|
||||
return data.Count;
|
||||
}
|
||||
}
|
||||
|
||||
bool IList.IsReadOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IList.IsFixedSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Adds a string with the specified value to the
|
||||
/// <see cref='System.Collections.Specialized.StringCollection'/> .</para>
|
||||
/// </devdoc>
|
||||
public int Add(string value) {
|
||||
return data.Add(value);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Copies the elements of a string array to the end of the <see cref='System.Collections.Specialized.StringCollection'/>.</para>
|
||||
/// </devdoc>
|
||||
public void AddRange(string[] value) {
|
||||
if (value == null) {
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
data.AddRange(value);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Removes all the strings from the
|
||||
/// <see cref='System.Collections.Specialized.StringCollection'/> .</para>
|
||||
/// </devdoc>
|
||||
public void Clear() {
|
||||
data.Clear();
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets a value indicating whether the
|
||||
/// <see cref='System.Collections.Specialized.StringCollection'/> contains a string with the specified
|
||||
/// value.</para>
|
||||
/// </devdoc>
|
||||
public bool Contains(string value) {
|
||||
return data.Contains(value);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Copies the <see cref='System.Collections.Specialized.StringCollection'/> values to a one-dimensional <see cref='System.Array'/> instance at the
|
||||
/// specified index.</para>
|
||||
/// </devdoc>
|
||||
public void CopyTo(string[] array, int index) {
|
||||
data.CopyTo(array, index);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Returns an enumerator that can iterate through
|
||||
/// the <see cref='System.Collections.Specialized.StringCollection'/> .</para>
|
||||
/// </devdoc>
|
||||
public StringEnumerator GetEnumerator() {
|
||||
return new StringEnumerator(this);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Returns the index of the first occurrence of a string in
|
||||
/// the <see cref='System.Collections.Specialized.StringCollection'/> .</para>
|
||||
/// </devdoc>
|
||||
public int IndexOf(string value) {
|
||||
return data.IndexOf(value);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Inserts a string into the <see cref='System.Collections.Specialized.StringCollection'/> at the specified
|
||||
/// index.</para>
|
||||
/// </devdoc>
|
||||
public void Insert(int index, string value) {
|
||||
data.Insert(index, value);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets a value indicating whether the <see cref='System.Collections.Specialized.StringCollection'/> is read-only.</para>
|
||||
/// </devdoc>
|
||||
public bool IsReadOnly {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets a value indicating whether access to the
|
||||
/// <see cref='System.Collections.Specialized.StringCollection'/>
|
||||
/// is synchronized (thread-safe).</para>
|
||||
/// </devdoc>
|
||||
public bool IsSynchronized {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para> Removes a specific string from the
|
||||
/// <see cref='System.Collections.Specialized.StringCollection'/> .</para>
|
||||
/// </devdoc>
|
||||
public void Remove(string value) {
|
||||
data.Remove(value);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Removes the string at the specified index of the <see cref='System.Collections.Specialized.StringCollection'/>.</para>
|
||||
/// </devdoc>
|
||||
public void RemoveAt(int index) {
|
||||
data.RemoveAt(index);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets an object that can be used to synchronize access to the <see cref='System.Collections.Specialized.StringCollection'/>.</para>
|
||||
/// </devdoc>
|
||||
public object SyncRoot {
|
||||
get {
|
||||
return data.SyncRoot;
|
||||
}
|
||||
}
|
||||
|
||||
object IList.this[int index] {
|
||||
get {
|
||||
return this[index];
|
||||
}
|
||||
set {
|
||||
this[index] = (string)value;
|
||||
}
|
||||
}
|
||||
|
||||
int IList.Add(object value) {
|
||||
return Add((string)value);
|
||||
}
|
||||
|
||||
bool IList.Contains(object value) {
|
||||
return Contains((string) value);
|
||||
}
|
||||
|
||||
|
||||
int IList.IndexOf(object value) {
|
||||
return IndexOf((string)value);
|
||||
}
|
||||
|
||||
void IList.Insert(int index, object value) {
|
||||
Insert(index, (string)value);
|
||||
}
|
||||
|
||||
void IList.Remove(object value) {
|
||||
Remove((string)value);
|
||||
}
|
||||
|
||||
void ICollection.CopyTo(Array array, int index) {
|
||||
data.CopyTo(array, index);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return data.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public class StringEnumerator {
|
||||
private System.Collections.IEnumerator baseEnumerator;
|
||||
private System.Collections.IEnumerable temp;
|
||||
|
||||
internal StringEnumerator(StringCollection mappings) {
|
||||
this.temp = (IEnumerable)(mappings);
|
||||
this.baseEnumerator = temp.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public string Current {
|
||||
get {
|
||||
return (string)(baseEnumerator.Current);
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public bool MoveNext() {
|
||||
return baseEnumerator.MoveNext();
|
||||
}
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
public void Reset() {
|
||||
baseEnumerator.Reset();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,458 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="StringDictionary.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
*/
|
||||
namespace System.Collections.Specialized {
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Diagnostics;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.ComponentModel.Design.Serialization;
|
||||
using System.Globalization;
|
||||
using System.Collections.Generic;
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Implements a hashtable with the key strongly typed to be
|
||||
/// a string rather than an object. </para>
|
||||
/// <para>Consider this class obsolete - use Dictionary<String, String> instead
|
||||
/// with a proper StringComparer instance.</para>
|
||||
/// </devdoc>
|
||||
[Serializable]
|
||||
[DesignerSerializer("System.Diagnostics.Design.StringDictionaryCodeDomSerializer, " + AssemblyRef.SystemDesign, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + AssemblyRef.SystemDesign)]
|
||||
// @
|
||||
public class StringDictionary : IEnumerable {
|
||||
|
||||
// For compatibility, we want the Keys property to return values in lower-case.
|
||||
// That means using ToLower in each property on this type. Also for backwards
|
||||
// compatibility, we will be converting strings to lower-case, which has a
|
||||
// problem for some Georgian alphabets. Can't really fix it now though...
|
||||
internal Hashtable contents = new Hashtable();
|
||||
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Initializes a new instance of the StringDictionary class.</para>
|
||||
/// <para>If you're using file names, registry keys, etc, you want to use
|
||||
/// a Dictionary<String, Object> and use
|
||||
/// StringComparer.OrdinalIgnoreCase.</para>
|
||||
/// </devdoc>
|
||||
public StringDictionary() {
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets the number of key-and-value pairs in the StringDictionary.</para>
|
||||
/// </devdoc>
|
||||
public virtual int Count {
|
||||
get {
|
||||
return contents.Count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Indicates whether access to the StringDictionary is synchronized (thread-safe). This property is
|
||||
/// read-only.</para>
|
||||
/// </devdoc>
|
||||
public virtual bool IsSynchronized {
|
||||
get {
|
||||
return contents.IsSynchronized;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets or sets the value associated with the specified key.</para>
|
||||
/// </devdoc>
|
||||
public virtual string this[string key] {
|
||||
get {
|
||||
if( key == null ) {
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
return (string) contents[key.ToLower(CultureInfo.InvariantCulture)];
|
||||
}
|
||||
set {
|
||||
if( key == null ) {
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
contents[key.ToLower(CultureInfo.InvariantCulture)] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets a collection of keys in the StringDictionary.</para>
|
||||
/// </devdoc>
|
||||
public virtual ICollection Keys {
|
||||
get {
|
||||
return contents.Keys;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets an object that can be used to synchronize access to the StringDictionary.</para>
|
||||
/// </devdoc>
|
||||
public virtual object SyncRoot {
|
||||
get {
|
||||
return contents.SyncRoot;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Gets a collection of values in the StringDictionary.</para>
|
||||
/// </devdoc>
|
||||
public virtual ICollection Values {
|
||||
get {
|
||||
return contents.Values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Adds an entry with the specified key and value into the StringDictionary.</para>
|
||||
/// </devdoc>
|
||||
public virtual void Add(string key, string value) {
|
||||
if( key == null ) {
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
contents.Add(key.ToLower(CultureInfo.InvariantCulture), value);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Removes all entries from the StringDictionary.</para>
|
||||
/// </devdoc>
|
||||
public virtual void Clear() {
|
||||
contents.Clear();
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Determines if the string dictionary contains a specific key</para>
|
||||
/// </devdoc>
|
||||
public virtual bool ContainsKey(string key) {
|
||||
if( key == null ) {
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
return contents.ContainsKey(key.ToLower(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Determines if the StringDictionary contains a specific value.</para>
|
||||
/// </devdoc>
|
||||
public virtual bool ContainsValue(string value) {
|
||||
return contents.ContainsValue(value);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Copies the string dictionary values to a one-dimensional <see cref='System.Array'/> instance at the
|
||||
/// specified index.</para>
|
||||
/// </devdoc>
|
||||
public virtual void CopyTo(Array array, int index) {
|
||||
contents.CopyTo(array, index);
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Returns an enumerator that can iterate through the string dictionary.</para>
|
||||
/// </devdoc>
|
||||
public virtual IEnumerator GetEnumerator() {
|
||||
return contents.GetEnumerator();
|
||||
}
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>Removes the entry with the specified key from the string dictionary.</para>
|
||||
/// </devdoc>
|
||||
public virtual void Remove(string key) {
|
||||
if( key == null ) {
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
contents.Remove(key.ToLower(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make this StringDictionary subservient to some other collection.
|
||||
/// <para>Some code was replacing the contents field with a Hashtable created elsewhere.
|
||||
/// While it may not have been incorrect, we don't want to encourage that pattern, because
|
||||
/// it will replace the IEqualityComparer in the Hashtable, and creates a possibly-undesirable
|
||||
/// link between two seemingly different collections. Let's discourage that somewhat by
|
||||
/// making this an explicit method call instead of an internal field assignment.</para>
|
||||
/// </summary>
|
||||
/// <param name="useThisHashtableInstead">Replaces the backing store with another, possibly aliased Hashtable.</param>
|
||||
internal void ReplaceHashtable(Hashtable useThisHashtableInstead) {
|
||||
contents = useThisHashtableInstead;
|
||||
}
|
||||
|
||||
internal IDictionary<string, string> AsGenericDictionary() {
|
||||
return new GenericAdapter(this);
|
||||
}
|
||||
|
||||
#region GenericAdapter
|
||||
//
|
||||
// This class is used to make StringDictionary implement IDictionary<string,string> indirectly.
|
||||
// This is done to prevent StringDictionary be serialized as IDictionary<string,string> and break its serialization by DataContractSerializer due to a bug in the serialization code.
|
||||
private class GenericAdapter : IDictionary<string, string>
|
||||
{
|
||||
|
||||
StringDictionary m_stringDictionary;
|
||||
|
||||
internal GenericAdapter(StringDictionary stringDictionary) {
|
||||
m_stringDictionary = stringDictionary;
|
||||
}
|
||||
|
||||
#region IDictionary<string, string> Members
|
||||
public void Add(string key, string value) {
|
||||
|
||||
// GenericAdapter.Add has the semantics of Item property to make ProcessStartInfo.Environment deserializable by DataContractSerializer.
|
||||
// ProcessStartInfo.Environment property does not have a setter
|
||||
// and so during deserialization the serializer initializes the property by calling get_Environment and
|
||||
// then populates it via IDictionary<,>.Add per item.
|
||||
// However since get_Environment gives the current snapshot of environment variables we might try to insert a key that already exists.
|
||||
// (For Example 'PATH') causing an exception. This implementation ensures that we overwrite values in case of duplication.
|
||||
|
||||
this[key] = value;
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key) {
|
||||
return m_stringDictionary.ContainsKey(key);
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
m_stringDictionary.Clear();
|
||||
}
|
||||
|
||||
public int Count {
|
||||
get {
|
||||
return m_stringDictionary.Count;
|
||||
}
|
||||
}
|
||||
|
||||
// Items added to allow StringDictionary to provide IDictionary<string, string> support.
|
||||
ICollectionToGenericCollectionAdapter _values;
|
||||
ICollectionToGenericCollectionAdapter _keys;
|
||||
|
||||
// IDictionary<string,string>.Item vs StringDictioanry.Item
|
||||
// IDictionary<string,string>.get_Item i. KeyNotFoundException when the property is retrieved and key is not found.
|
||||
// StringBuilder.get_Item i. Returns null in case the key is not found.
|
||||
public string this[string key] {
|
||||
get {
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
if (!m_stringDictionary.ContainsKey(key)) throw new KeyNotFoundException();
|
||||
|
||||
return m_stringDictionary[key];
|
||||
}
|
||||
set {
|
||||
if (key == null) {
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
m_stringDictionary[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// This method returns a read-only view of the Keys in the StringDictinary.
|
||||
public ICollection<string> Keys {
|
||||
get {
|
||||
if( _keys == null ) {
|
||||
_keys = new ICollectionToGenericCollectionAdapter(m_stringDictionary, KeyOrValue.Key);
|
||||
}
|
||||
return _keys;
|
||||
}
|
||||
}
|
||||
|
||||
// This method returns a read-only view of the Values in the StringDictionary.
|
||||
public ICollection<string> Values {
|
||||
get {
|
||||
if( _values == null ) {
|
||||
_values = new ICollectionToGenericCollectionAdapter(m_stringDictionary, KeyOrValue.Value);
|
||||
}
|
||||
return _values;
|
||||
}
|
||||
}
|
||||
|
||||
// IDictionary<string,string>.Remove vs StringDictionary.Remove.
|
||||
// IDictionary<string,string>.Remove- i. Returns a bool status that represents success\failure.
|
||||
// ii. Returns false in case key is not found.
|
||||
// StringDictionary.Remove i. Does not return the status and does nothing in case key is not found.
|
||||
public bool Remove(string key) {
|
||||
|
||||
// Check if the key is not present and return false.
|
||||
if (!m_stringDictionary.ContainsKey(key)) return false;
|
||||
|
||||
// We call the virtual StringDictionary.Remove method to ensure any subClass gets the expected behavior.
|
||||
m_stringDictionary.Remove(key);
|
||||
|
||||
// If the above call has succeeded we simply return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public bool TryGetValue(string key, out string value) {
|
||||
if (!m_stringDictionary.ContainsKey(key)) {
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
value = m_stringDictionary[key];
|
||||
return true;
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<string, string>>.Add(KeyValuePair<string, string> item) {
|
||||
m_stringDictionary.Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<string, string>>.Contains(KeyValuePair<string, string> item) {
|
||||
string value;
|
||||
return TryGetValue(item.Key, out value) && value.Equals(item.Value);
|
||||
}
|
||||
|
||||
void ICollection<KeyValuePair<string, string>>.CopyTo(KeyValuePair<string, string>[] array, int arrayIndex) {
|
||||
if( array == null )
|
||||
throw new ArgumentNullException("array", SR.GetString(SR.ArgumentNull_Array));
|
||||
if( arrayIndex < 0 )
|
||||
throw new ArgumentOutOfRangeException("arrayIndex", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNum));
|
||||
if( array.Length - arrayIndex < Count )
|
||||
throw new ArgumentException(SR.GetString(SR.Arg_ArrayPlusOffTooSmall));
|
||||
|
||||
int index = arrayIndex;
|
||||
|
||||
foreach (DictionaryEntry entry in m_stringDictionary) {
|
||||
array[index++] = new KeyValuePair<string, string>((string)entry.Key, (string)entry.Value);
|
||||
}
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<string,string>>.IsReadOnly {
|
||||
get {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ICollection<KeyValuePair<string, string>>.Remove vs StringDictionary.Remove
|
||||
// ICollection<KeyValuePair<string, string>>.Remove - i. Return status.
|
||||
// ii. Returns false in case the items is not found.
|
||||
// StringDictionary.Remove i. Does not return a status and does nothing in case the key is not found.
|
||||
bool ICollection<KeyValuePair<string, string>>.Remove(KeyValuePair<string, string> item) {
|
||||
|
||||
// If the item is not found return false.
|
||||
ICollection<KeyValuePair<string, string>> iCollection = this;
|
||||
if( !iCollection.Contains(item) ) return false;
|
||||
|
||||
// We call the virtual StringDictionary.Remove method to ensure any subClass gets the expected behavior.
|
||||
m_stringDictionary.Remove(item.Key);
|
||||
|
||||
// If the above call has succeeded we simply return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return this.GetEnumerator();
|
||||
}
|
||||
|
||||
// The implementation asummes that this.GetEnumerator().Current can be casted to DictionaryEntry.
|
||||
// and although StringDictionary.GetEnumerator() returns IEnumerator and is a virtual method
|
||||
// it should be ok to take that assumption since it is an implicit contract.
|
||||
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
|
||||
{
|
||||
foreach (DictionaryEntry dictionaryEntry in m_stringDictionary)
|
||||
yield return new KeyValuePair<string, string>((string)dictionaryEntry.Key, (string)dictionaryEntry.Value);
|
||||
}
|
||||
|
||||
internal enum KeyOrValue // Used internally for IDictionary<string, string> support
|
||||
{
|
||||
Key,
|
||||
Value
|
||||
}
|
||||
|
||||
// This Adapter converts StringDictionary.Keys and StringDictionary.Values to ICollection<string>
|
||||
// Since StringDictionary implements a virtual StringDictionary.Keys and StringDictionary.Values
|
||||
private class ICollectionToGenericCollectionAdapter : ICollection<string> {
|
||||
|
||||
StringDictionary _internal;
|
||||
KeyOrValue _keyOrValue;
|
||||
|
||||
public ICollectionToGenericCollectionAdapter(StringDictionary source, KeyOrValue keyOrValue) {
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
|
||||
_internal = source;
|
||||
_keyOrValue = keyOrValue;
|
||||
}
|
||||
|
||||
public void Add(string item) {
|
||||
ThrowNotSupportedException();
|
||||
}
|
||||
|
||||
public void Clear() {
|
||||
ThrowNotSupportedException();
|
||||
}
|
||||
|
||||
public void ThrowNotSupportedException() {
|
||||
if( _keyOrValue == KeyOrValue.Key ) {
|
||||
throw new NotSupportedException(SR.GetString(SR.NotSupported_KeyCollectionSet)); //Same as KeyCollection/ValueCollection
|
||||
}
|
||||
throw new NotSupportedException(SR.GetString(SR.NotSupported_ValueCollectionSet)); //Same as KeyCollection/ValueCollection
|
||||
}
|
||||
|
||||
|
||||
public bool Contains(string item) {
|
||||
// The underlying backing store for the StringDictionary is a HashTable so we
|
||||
// want to delegate Contains to respective ContainsKey/ContainsValue functionality
|
||||
// depending upon whether we are using Keys or Value collections.
|
||||
|
||||
if( _keyOrValue == KeyOrValue.Key ) {
|
||||
return _internal.ContainsKey(item);
|
||||
}
|
||||
return _internal.ContainsValue(item);
|
||||
}
|
||||
|
||||
public void CopyTo(string[] array, int arrayIndex) {
|
||||
var collection = GetUnderlyingCollection();
|
||||
collection.CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
public int Count {
|
||||
get {
|
||||
return _internal.Count; // hashtable count is same as key/value count.
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsReadOnly {
|
||||
get {
|
||||
return true; //Same as KeyCollection/ValueCollection
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(string item) {
|
||||
ThrowNotSupportedException();
|
||||
return false;
|
||||
}
|
||||
|
||||
private ICollection GetUnderlyingCollection() {
|
||||
if( _keyOrValue == KeyOrValue.Key ) {
|
||||
return (ICollection) _internal.Keys;
|
||||
}
|
||||
return (ICollection) _internal.Values;
|
||||
}
|
||||
|
||||
public IEnumerator<string> GetEnumerator() {
|
||||
ICollection collection = GetUnderlyingCollection();
|
||||
|
||||
// This is doing the same as collection.Cast<string>()
|
||||
foreach (string entry in collection) {
|
||||
yield return entry;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return GetUnderlyingCollection().GetEnumerator();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="StringDictionaryWithComparer.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// StringDictionary compares keys by converting them to lowercase first, using the Invariant culture.
|
||||
// This is not the right thing to do for file names, registry keys, environment variable etc.
|
||||
// This internal version of StringDictionary accepts an IEqualityComparer and enables you to
|
||||
// customize the string comparison to be StringComparer.OrdinalIgnoreCase for the above cases.
|
||||
|
||||
namespace System.Collections.Specialized {
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Diagnostics;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.ComponentModel.Design.Serialization;
|
||||
using System.Globalization;
|
||||
|
||||
[Serializable]
|
||||
internal class StringDictionaryWithComparer : StringDictionary {
|
||||
|
||||
public StringDictionaryWithComparer() : this(StringComparer.OrdinalIgnoreCase) {
|
||||
}
|
||||
|
||||
public StringDictionaryWithComparer(IEqualityComparer comparer) {
|
||||
ReplaceHashtable(new Hashtable(comparer));
|
||||
}
|
||||
|
||||
public override string this[string key] {
|
||||
get {
|
||||
if( key == null ) {
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
return (string) contents[key];
|
||||
}
|
||||
set {
|
||||
if( key == null ) {
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
contents[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Add(string key, string value) {
|
||||
if( key == null ) {
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
contents.Add(key, value);
|
||||
}
|
||||
|
||||
public override bool ContainsKey(string key) {
|
||||
if( key == null ) {
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
return contents.ContainsKey(key);
|
||||
}
|
||||
|
||||
public override void Remove(string key) {
|
||||
if( key == null ) {
|
||||
throw new ArgumentNullException("key");
|
||||
}
|
||||
|
||||
contents.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user