2010-06-02 18 views
11

Tôi đã có một trường IDictionary mà tôi muốn hiển thị thông qua thuộc tính kiểu IDictionary<string, dynamic> việc chuyển đổi đáng ngạc nhiên là khó vì tôi không biết mình có thể .Cast<>() từ điển IDictionary.Cách tốt nhất để dịch từ IDictionary sang IDictionary chung là

tốt nhất tôi đã có:

IDictionary properties; 
protected virtual IDictionary<string, dynamic> Properties { 
    get { 
     return _properties.Keys.Cast<string>() 
       .ToDictionary(name=>name, name=> _properties[name] as dynamic); 
     } 
    } 
+2

Mã mẫu mới của bạn sẽ sao chép dữ liệu trong IDictionary * mỗi lần được gọi là *. – Randolpho

+4

cách duy nhất để được cập nhật –

+0

Rất đúng. Tuy nhiên, bạn có thể thử tùy chọn mới được đề xuất của tôi 2. Mặc dù sẽ có bản sao nếu 'Keys' hoặc' Values' được gọi, nó sẽ luôn được cập nhật, trong khi dịch từ kiểu này sang kiểu khác. – Randolpho

Trả lời

5

Nếu loại cơ bản của IDictionary không thực hiện IDictionary<string, dynamic>, bạn không thể cast đối tượng, thời gian. Nếu có, dàn diễn viên đơn giản qua (IDictionary<string, dynamic>)localVar sẽ đủ.

Nếu không, có hai điều bạn có thể làm:

  1. Sao chép IDictionary để loại generic của bạn.
  2. Tạo một lớp Adapter chấp nhận IDictionary làm phụ thuộc và thực hiện các yêu cầu chung IDictionary bạn muốn, ánh xạ cuộc gọi từ một đến người khác.

Edit: Các mẫu mã bạn vừa đăng tải sẽ sao chép các từ điển mỗi khi nó được gọi là! Tôi sẽ chỉnh sửa lại trong giây lát với một số mã được đề xuất.

Lựa chọn 1

cách tiếp cận mẫu mã của bạn là rắn như một phương tiện sao chép dữ liệu, nhưng các bản sao nên được lưu trữ hoặc bạn sẽ sao chép nhiều lần. Tôi khuyên bạn nên đặt mã dịch thực tế vào một phương thức riêng biệt và gọi nó từ tài sản của bạn lần đầu tiên nó được sử dụng. Ví dụ:

private IDictionary dataLayerProperties; 
private IDictionary<string, dynamic> translatedProperties = null; 
protected virtual IDictionary<string, dynamic> Properties 
{ 
    if(translatedProperties == null) 
    { 
     translatedProperties = TranslateDictionary(dataLayerProperties);   
    } 
    return translatedProperties; 
} 

public IDictionary<string, dynamic> TranslateDictionary(IDictionary values) 
{ 
    return values.Keys.Cast<string>().ToDictionary(key=>key, key => values[key] as dynamic);    
} 

Bây giờ, có những nhược điểm rõ ràng cho cách tiếp cận này ... nếu dataLayerProperties cần được làm mới thì sao? Bạn phải đi thiết translatedProperties null lần nữa, vv

Lựa chọn 2

Đây là phương pháp ưa thích của tôi.

public class TranslatedDictionary : IDictionary<string, dynamic> 
{ 
    private IDictionary Original = null; 

    public TranslatedDictionary(IDictionary original) 
    { 
     Original = original; 
    } 
    public ICollection<string> Keys 
    { 
     get 
     { 
      return Original.Keys.Cast<string>().ToList(); 
     } 
    } 

    public dynamic this[string key] 
    { 
     get 
     { 
      return Original[key] as dynamic; 
     } 
     set 
     { 
      Original[key] = value; 
     } 
    } 
    // and so forth, for each method of IDictionary<string, dynamic> 
} 

//elsewhere, using your original property and field names: 
Properties = new TranslatedDictionary(properties); 

Giờ đây, có khuyết điểm rõ ràng để phương pháp này là tốt, những rõ ràng nhất là một thực tế rằng Keys (và giá trị gia tăng và bất cứ điều gì khác mà trả ICollection trên IDictionary đã trở lại một mảng mới cho mỗi cuộc gọi. Nhưng này vẫn cho phép các cách tiếp cận linh hoạt nhất, vì nó đảm bảo dữ liệu luôn được cập nhật.

+0

Tôi đã cung cấp một triển khai đầy đủ bên dưới cho phương pháp ưa thích do Randolpho đề xuất. –

-1

Bạn cần phải sử dụng một KeyValuePair.

myDictionary.Cast<KeyValuePair<Type1, Type2>>() 
+0

Ach, tôi trả lời quá nhanh. Truyền sẽ trả về một số đếm. Nếu bạn muốn nó là một IDictionary thì bạn thực sự không thể tránh việc tạo từ điển mới, ít nhất là với các phương thức mở rộng mà tôi quen thuộc. Có thể chuyển myDictionary.Cast >() .Từ điển (kv => kv.Key, kv => kv.Value) để làm cho dễ dàng hơn ít nhất .. Mặc dù tất nhiên bạn sẽ không ' t muốn đặt nó trên một tài sản getter, cho công việc đó. Giải pháp tốt hơn là triển khai IDictionary với lớp học tham chiếu IDictionary và phôi khi cần thiết. – scobi

2

Trừ khi loại hậu thuẫn cho IDictionary dụ đã thực hiện IDictionary<string,dynamic> (như Dictionary<string,dynamic>) sau đó đúc sẽ không giúp bạn. phương pháp Cast<>() là chỉ hữu ích khi trả về các giá trị IEnumerable<T> và bình thường c asting không phải là một lựa chọn.

Nếu việc cung cấp dữ liệu dưới dạng IDictionary<string,dynamic> là quan trọng, thì tại sao không tiếp tục và lưu trữ dữ liệu dưới dạng Dictionary<string,dynamic> ngay từ đầu?

+0

gây ra thành phần động nhibernate sử dụng IDictionary –

+1

@George Mauer: sau đó bạn sẽ phải sao chép hoặc dịch. Bạn không thể đúc. – Randolpho

+0

Vâng, tôi đoán diễn viên quá mạnh một thuật ngữ - tôi đang tìm cách tốt nhất để dịch. –

1

Dưới đây là cách triển khai hoàn chỉnh phương pháp được đề xuất trong câu trả lời hàng đầu. Điều này quá lớn để vừa vặn như một bình luận.

using System; 
    using System.Collections; 
    using System.Collections.Generic; 
    using System.Diagnostics.CodeAnalysis; 
    using System.Linq; 

    /// <summary> 
    /// The casted dictionary. 
    /// </summary> 
    /// <typeparam name="TKey"> 
    /// The key type 
    /// </typeparam> 
    /// <typeparam name="TValue"> 
    /// The value type 
    /// </typeparam> 
    public class CastedDictionary<TKey, TValue> : IDictionary<TKey, TValue> 
    { 
     /// <summary> 
     /// The original dictionary. 
     /// </summary> 
     private readonly IDictionary originalDictionary; 

     /// <summary> 
     /// The keys. 
     /// </summary> 
     private ICollection<TKey> keys; 

     /// <summary> 
     /// The values. 
     /// </summary> 
     private ICollection<TValue> values; 

     /// <summary> 
     /// Initializes a new instance of the <see cref="CastedDictionary{TKey,TValue}"/> class. 
     /// </summary> 
     /// <param name="original"> 
     /// The original. 
     /// </param> 
     public CastedDictionary(IDictionary original) 
      : this() 
     { 
      if (original == null) 
      { 
       throw new ArgumentNullException("original"); 
      } 

      this.originalDictionary = original; 
     } 

     /// <summary> 
     /// Prevents a default instance of the <see cref="CastedDictionary{TKey, TValue}"/> class from being created. 
     /// </summary> 
     [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1642:ConstructorSummaryDocumentationMustBeginWithStandardText", Justification = "Style Cop does not analyze private generic class constructor comments properly")] 
     private CastedDictionary() 
     { 
     } 

     /// <summary> 
     /// Gets the number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
     /// </summary> 
     /// <returns> 
     /// The number of elements contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
     /// </returns> 
     public int Count 
     { 
      get 
      { 
       return this.originalDictionary.Count; 
      } 
     } 

     /// <summary> 
     /// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. 
     /// </summary> 
     /// <returns> 
     /// true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false. 
     /// </returns> 
     public bool IsReadOnly 
     { 
      get 
      { 
       return this.originalDictionary.IsReadOnly; 
      } 
     } 

     /// <summary> 
     /// Gets an <see cref="T:System.Collections.Generic.ICollection`1"/> containing the keys of the <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
     /// </summary> 
     /// <returns> 
     /// An <see cref="T:System.Collections.Generic.ICollection`1"/> containing the keys of the object that implements <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
     /// </returns> 
     public ICollection<TKey> Keys 
     { 
      get 
      { 
       return this.keys ?? (this.keys = this.originalDictionary.Keys.Cast<TKey>().ToList()); 
      } 
     } 

     /// <summary> 
     /// Gets an <see cref="T:System.Collections.Generic.ICollection`1"/> containing the values in the <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
     /// </summary> 
     /// <returns> 
     /// An <see cref="T:System.Collections.Generic.ICollection`1"/> containing the values in the object that implements <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
     /// </returns> 
     public ICollection<TValue> Values 
     { 
      get 
      { 
       return this.values ?? (this.values = this.originalDictionary.Values.Cast<TValue>().ToList()); 
      } 
     } 

     /// <summary> 
     /// Gets or sets the element with the specified key. 
     /// </summary> 
     /// <returns> 
     /// The element with the specified key. 
     /// </returns> 
     /// <param name="key">The key of the element to get or set.</param><exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception><exception cref="T:System.Collections.Generic.KeyNotFoundException">The property is retrieved and <paramref name="key"/> is not found.</exception><exception cref="T:System.NotSupportedException">The property is set and the <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.</exception> 
     public TValue this[TKey key] 
     { 
      get 
      { 
       return (TValue)this.originalDictionary[key]; 
      } 

      set 
      { 
       this.originalDictionary[key] = value; 
      } 
     } 

     /// <summary> 
     /// Returns an enumerator that iterates through the collection. 
     /// </summary> 
     /// <returns> 
     /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection. 
     /// </returns> 
     /// <filterpriority>1</filterpriority> 
     public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() 
     { 
      return this.originalDictionary.Cast<KeyValuePair<TKey, TValue>>().GetEnumerator(); 
     } 

     /// <summary> 
     /// Returns an enumerator that iterates through a collection. 
     /// </summary> 
     /// <returns> 
     /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection. 
     /// </returns> 
     /// <filterpriority>2</filterpriority> 
     IEnumerator IEnumerable.GetEnumerator() 
     { 
      return this.GetEnumerator(); 
     } 

     /// <summary> 
     /// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
     /// </summary> 
     /// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception> 
     public void Add(KeyValuePair<TKey, TValue> item) 
     { 
      this.originalDictionary.Add(item.Key, item.Value); 
     } 

     /// <summary> 
     /// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
     /// </summary> 
     /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. </exception> 
     public void Clear() 
     { 
      this.originalDictionary.Clear(); 
     } 

     /// <summary> 
     /// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value. 
     /// </summary> 
     /// <returns> 
     /// true if <paramref name="item"/> is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. 
     /// </returns> 
     /// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param> 
     public bool Contains(KeyValuePair<TKey, TValue> item) 
     { 
      return this.originalDictionary.Contains(item.Key) && EqualityComparer<TValue>.Default.Equals(this[item.Key], item.Value); 
     } 

     /// <summary> 
     /// Copies the elements of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index. 
     /// </summary> 
     /// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param><param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null.</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="arrayIndex"/> is less than 0.</exception><exception cref="T:System.ArgumentException">The number of elements in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.</exception> 
     public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) 
     { 
      this.originalDictionary.CopyTo(array, arrayIndex); 
     } 

     /// <summary> 
     /// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
     /// </summary> 
     /// <returns> 
     /// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>. 
     /// </returns> 
     /// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception> 
     public bool Remove(KeyValuePair<TKey, TValue> item) 
     { 
      if (this.Contains(item)) 
      { 
       this.originalDictionary.Remove(item.Key); 
       return true; 
      } 

      return false; 
     } 

     /// <summary> 
     /// Determines whether the <see cref="T:System.Collections.Generic.IDictionary`2"/> contains an element with the specified key. 
     /// </summary> 
     /// <returns> 
     /// true if the <see cref="T:System.Collections.Generic.IDictionary`2"/> contains an element with the key; otherwise, false. 
     /// </returns> 
     /// <param name="key">The key to locate in the <see cref="T:System.Collections.Generic.IDictionary`2"/>.</param><exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception> 
     public bool ContainsKey(TKey key) 
     { 
      return this.originalDictionary.Contains(key); 
     } 

     /// <summary> 
     /// Adds an element with the provided key and value to the <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
     /// </summary> 
     /// <param name="key">The object to use as the key of the element to add.</param><param name="value">The object to use as the value of the element to add.</param><exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception><exception cref="T:System.ArgumentException">An element with the same key already exists in the <see cref="T:System.Collections.Generic.IDictionary`2"/>.</exception><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.</exception> 
     public void Add(TKey key, TValue value) 
     { 
      this.originalDictionary.Add(key, value); 
     } 

     /// <summary> 
     /// Removes the element with the specified key from the <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
     /// </summary> 
     /// <returns> 
     /// true if the element is successfully removed; otherwise, false. This method also returns false if <paramref name="key"/> was not found in the original <see cref="T:System.Collections.Generic.IDictionary`2"/>. 
     /// </returns> 
     /// <param name="key">The key of the element to remove.</param><exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.IDictionary`2"/> is read-only.</exception> 
     public bool Remove(TKey key) 
     { 
      if (this.ContainsKey(key)) 
      { 
       this.originalDictionary.Remove(key); 
       return true; 
      } 

      return false; 
     } 

     /// <summary> 
     /// Gets the value associated with the specified key. 
     /// </summary> 
     /// <returns> 
     /// true if the object that implements <see cref="T:System.Collections.Generic.IDictionary`2"/> contains an element with the specified key; otherwise, false. 
     /// </returns> 
     /// <param name="key">The key whose value to get.</param><param name="value">When this method returns, the value associated with the specified key, if the key is found; otherwise, the default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized.</param><exception cref="T:System.ArgumentNullException"><paramref name="key"/> is null.</exception> 
     public bool TryGetValue(TKey key, out TValue value) 
     { 
// ReSharper disable CompareNonConstrainedGenericWithNull 
      if (typeof(TKey).IsValueType == false && key == null) 
// ReSharper restore CompareNonConstrainedGenericWithNull 
      { 
       throw new ArgumentNullException("key"); 
      } 

      if (this.ContainsKey(key)) 
      { 
       value = this[key]; 
       return true; 
      } 

      value = default(TValue); 
      return false; 
     } 
    } 
+0

Tôi có thể đề xuất tên 'Phù hợp ',' GenericDictionary' hoặc một cái gì đó khác thay vì 'CastedDictionary', vì quá khứ * cast * không được * cast * nhưng * cast *? 'CastedDictionary' rất khó xử ... – ErikE

Các vấn đề liên quan