Can we make our own List<string, string, string> in C#.NET? I need to make a list having 3 different strings as a single element in the list.
You can certainly create your own class called List with three generic type parameters. I would strongly discourage you from doing so though. It would confuse the heck out of anyone using your code.
Instead, either use List<Tuple<string, string, string>> (if you're using .NET 4, anyway) or (preferrably) create your own class to encapsulate those three strings in a meaningful way, then use List<YourNewClass>.
Creating your own class will make it much clearer when you're writing and reading the code - by giving names to the three different strings involved, everyone will know what they're meant to mean. You can also give more behaviour to the class as and when you need to.
You can use a Tuple to achieve that.
For example:
var list = new List<Tuple<string,string,string>>();
to iterate over the values you may want to do a simple:
list.ForEach(x=>{
//x is a Tuple
});
or to find some specific tupple, you may want to do the folowing:
var list = new List<Tuple<string,string,string>>{
new Tuple<string,string,string>("Hello", "Holla", "Ciao"),
new Tuple<string,string,string>("Buy", "--", "Ciao")
};
list.Where(x=>x.Item2 == "--");
This will return the last Tuple.
You can use a list of tuples. Like so:
List<Tuple<string, string, string>>
Maybe something like this:
var ls= new List<Tuple<string,string,string>>();
I recommend this solution
public class MyCustomClass
{
public string MyString1 { get; set; }
public string MyString2 { get; set; }
public string MyString3 { get; set; }
}
class MyApp
{
public MyApp()
{
List<MyCustomClass> customList = new List<MyCustomClass>();
customList.Add(new MyCustomClass
{
MyString1 = "Hello",
MyString2 = "Every",
MyString3 = "Body",
});
}
}
For example:
var list = new List<Tuple<string, string, string>>();
var tuple = Tuple.Create("a", "b", "c");
list.Add(tuple);
For more information, look in MSDN.
How about making a List<Tuple<string, string, string>> ?
A better idea might be though, if each of the strings has a specific meaning, to put them all into a class and then create a List of that.
Anyone tried dynamic ?
var list = new List<dynamic>();
list.Add(new { Name = "SampleN", Address = "SampleA", Email = "SampleE" });
var name = list[0].Name;
No, sadly this does't work. The best you can do is to create a List of Lists, or utilise some form of implementation of the IDictionary interface.
Although, that said, if you have three items of data which belong together in this manner, it's probably worthwhile creating a class to contain them.
That would then give you the opportunity to pass a List around your application and assign meaningful names to each data item. Never underestimate the power of readability six months down the line.
You may define a List and implement the needed interfaces(such as IList). Codes blow.
public class List<T1, T2, T3> : IList
{
#region IList Members
public int Add(object value)
{
throw new NotImplementedException();
}
public void Clear()
{
throw new NotImplementedException();
}
public bool Contains(object value)
{
throw new NotImplementedException();
}
public int IndexOf(object value)
{
throw new NotImplementedException();
}
public void Insert(int index, object value)
{
throw new NotImplementedException();
}
public bool IsFixedSize
{
get { throw new NotImplementedException(); }
}
public bool IsReadOnly
{
get { throw new NotImplementedException(); }
}
public void Remove(object value)
{
throw new NotImplementedException();
}
public void RemoveAt(int index)
{
throw new NotImplementedException();
}
public object this[int index]
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
#endregion
#region ICollection Members
public void CopyTo(Array array, int index)
{
throw new NotImplementedException();
}
public int Count
{
get { throw new NotImplementedException(); }
}
public bool IsSynchronized
{
get { throw new NotImplementedException(); }
}
public object SyncRoot
{
get { throw new NotImplementedException(); }
}
#endregion
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
throw new NotImplementedException();
}
#endregion
}
However, List<Tuple<string,string,string>> is recommended.
public class Listt< T, T1, T2>
{
public Listt()
{
}
public void Add(T item, T1 item1, T2 item3)
{
}
}
public partial class MyApp : Window
{
public MyApp()
{
InitializeComponent();
Listt<string, string, string> customList = new Listt<string, string, string>();
customList.Add("we","are","here");
}
}
Related
I have created the two different classes. One class inherited from IList and another one class inherited from ObservableCollection. When we create the instance for those classes, I got the below results.
Inherited from IList
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Cells = new CellCollection();
}
private CellCollection cells;
public CellCollection Cells
{
get { return cells; }
set { cells = value; }
}
}
public class CellCollection : IList<OrderInfo>
{
public CellCollection()
{
}
public OrderInfo this[int index] { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public bool IsReadOnly => throw new NotImplementedException();
public int Count => throw new NotImplementedException();
public void Clear()
{
throw new NotImplementedException();
}
public bool Contains(OrderInfo item)
{
throw new NotImplementedException();
}
public void CopyTo(OrderInfo[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public IEnumerator<OrderInfo> GetEnumerator()
{
throw new NotImplementedException();
}
public int IndexOf(OrderInfo item)
{
throw new NotImplementedException();
}
public void Insert(int index, OrderInfo item)
{
throw new NotImplementedException();
}
public bool Remove(OrderInfo item)
{
throw new NotImplementedException();
}
public void RemoveAt(int index)
{
throw new NotImplementedException();
}
internal void Add(OrderInfo orderInfo)
{
}
void ICollection<OrderInfo>.Add(OrderInfo item)
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
Instance maintained for IList.
Inherited from ObservableCollection
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Cells = new CellCollection();
}
private CellCollection cells;
public CellCollection Cells
{
get { return cells; }
set { cells = value; }
}
}
public class CellCollection : ObservableCollection<OrderInfo>
{
public CellCollection()
{
}
}
Instance not maintained for Observable collection, Count only maintained
Could you explain the difference for both?
The debugger makes use of the debugger attributes the type is annotated with.
If a type does not use these attributes, the ToString() method of that type is called to get a text representation.
The ObservableCollection uses one of these methods to display the Count. Your own List implementation does none of this, so the base ToString() method is called which only returns the type name.
So to get a similar result for your own type, implement ToString() or annotate your CellCollection class with a DebuggerDisplayAttribute.
When the cursor is over a variable, you can see the variable name and the instance's debug label.
By default, the debug label is the result of ToString. For your class CellList, the method ToString cam from the base class Object and return the class's name. This display : CellList.
The attribute DebuggerDisplay allows define the instance's debug label (not to string). The class CellCollection inherit from ObservableCollection<T> than inherit from Collection<T> and the class Collection is declared with the attribute DebuggerDisplay.
[DebuggerDisplay("Count = {Count}")]
public class Collection<T>: IList<T>, IList, IReadOnlyList<T>
It's the same with all collection in .NET, like List.
If you set this attribute on your class CellList, you will see the same debug label.
I have a bit of a complex dictionary.
It's a dictionary which holds two enumerated types & a List<>
Dictionary<BiomeType, Dictionary<LocationType, List<string>>> myDictionary;
So when I want to use it, I do something like this:
//Add "myString" to the List<string>
myDictionary[BiomeType.Jungle][LocationType.City1].Add("myString"));
When I try to add "myString" to myList, it throws an obvious & foreseeable error: "KeyNotFoundException: The given key was not present in the dictionary."
Is there any way in C# to automatically have the Dictionary add the Key if it isn't already there? I have a lot of BiomeTypes & even more LocationTypes. It would be a PITA to have to create each List, then create each locationtype dictionary, and then to add it for every BiomeType. All that work just to initialize this complex dictionary. Is there no easy way to do this?
I'm using this for gamedev, to store objects in a Dictionary, so I can access them by doing something like
BiomeType playerCurrentBiomeType;
LocationType playerCurrentLocationType;
LoadLevel(myDictionary[playerCurrentBiomeType][playerCurrentLocationType]);
//ex. myDictionary[BiomeType.Jungle][LocationType.CapitalCity]
//ex. myDictionary[BiomeType.Desert][LocationType.CapitalCity]
//ex. myDictionary[BiomeType.Desert][LocationType.City3]
Perhaps, you can try this:
Dictionary<BiomeType, Dictionary<LocationType, List<string>>> myDictionary = new Dictionary<BiomeType, Dictionary<LocationType, List<string>>>();
BiomeType playerCurrentBiomeType;
LocationType playerCurrentLocationType;
if(!myDictionary.ContainsKey(playerCurrentBiomeType))
{
myDictionary.Add(playerCurrentBiomeType, new Dictionary<LocationType , List<string>>{{playerCurrentLocationType, new List<string>()}});
}
myDictionary[playerCurrentBiomeType][playerCurrentLocationType].Add("bla");
You could do this (although to be honest I'm not sure you should!)
The class below is a type that generally acts like a dictionary, does what you asked for, and has some other changes to hide from you the empty items it creates every time you ask the indexer for an item that doesn't exist.
public class SmellyDictionary<T1, T2>: IDictionary<T1, T2>, ICollection where T2 : ICollection, new()
{
private readonly IDictionary<T1, T2> _dict = new Dictionary<T1, T2>();
public T2 this[T1 key]
{
get
{
T2 value;
if (!_dict.TryGetValue(key, out value))
_dict[key] = value = new T2(); // This stinks!
return value;
}
set { _dict[key] = value; }
}
public bool Contains(KeyValuePair<T1, T2> item)
{
return _dict.Contains(item);
}
public bool ContainsKey(T1 key)
{
return _dict.ContainsKey(key) && _dict[key].Count > 0; // This hides the smell
}
public int Count { get { return _dict.Count(kvp => kvp.Value.Count > 0); } } // This hides the smell
public void Add(T1 key, T2 value)
{
T2 currentValue;
if (_dict.TryGetValue(key, out currentValue) && currentValue.Count > 0)
throw new ArgumentException("A non empty element with the same key already exists in the SmellyDictionary");
_dict[key] = value;
}
public void Add(KeyValuePair<T1, T2> item)
{
Add(item.Key, item.Value);
}
public bool Remove(T1 key)
{
return _dict.Remove(key);
}
public bool Remove(KeyValuePair<T1, T2> item)
{
return _dict.Remove(item);
}
public bool TryGetValue(T1 key, out T2 value)
{
return _dict.TryGetValue(key, out value);
}
public ICollection<T1> Keys { get { return _dict.Keys; } }
public ICollection<T2> Values { get { return _dict.Values; } }
public object SyncRoot { get { return ((ICollection)_dict).SyncRoot; } }
public bool IsSynchronized { get { return ((ICollection)_dict).IsSynchronized; } }
public IEnumerator<KeyValuePair<T1, T2>> GetEnumerator()
{
return _dict.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Clear()
{
_dict.Clear();
}
public void CopyTo(Array array, int index)
{
_dict.CopyTo((KeyValuePair<T1, T2>[])array, index);
}
public void CopyTo(KeyValuePair<T1, T2>[] array, int arrayIndex)
{
_dict.CopyTo(array, arrayIndex);
}
public bool IsReadOnly { get { return _dict.IsReadOnly; } }
}
Here's a slightly more sensible option. Just call this method to add a string to your dictionary.
private void AddCityToDictionary(Dictionary<BiomeType, Dictionary<LocationType, List<string>>> myDictionary, BiomeType biome, LocationType location, string city)
{
Dictionary<LocationType, List<string>> locationDictionary;
if (!myDictionary.TryGetValue(biome, out locationDictionary))
locationDictionary = myDictionary[biome] = new Dictionary<LocationType, List<string>>();
List<string> cityList;
if (!locationDictionary.TryGetValue(location, out cityList))
cityList = locationDictionary[location] = new List<string>();
cityList.Add(city);
}
Simply looping through every possible enum type & adding in a new value works to fully populate this multi-dimensional dictionary.
Dictionary<BiomeType, Dictionary<LocationType, List<string>>> myDictionary = new Dictionary<BiomeType, Dictionary<LocationType, List<string>>>(); //No thanks to troll users like Peter.
foreach (BiomeType biomeType in System.Enum.GetValues(typeof(BiomeType)))
{
Dictionary<LocationType, List<string>> newLocDict = new Dictionary<LocationType, List<string>>(); //No thanks to troll users like Peter.
foreach (LocationType locType in System.Enum.GetValues(typeof(LocationType)))
{
List<string> newList = new List<string>();
newLocDict.Add(locType, newList); //Add the final bit here & voila! Finished! No thanks to troll users like Peter.
}
myDictionary.Add(biomeType, newLocDict);
}
Robyn's solution works the same way if you don't want to fully populate the container with ALL enum values.
I want to write an interface which allows freedom in the implementation. Basically I don't know the return types neither param types of the methods. I just want derived classes to implement this contract with same method names and param numbers.
So I can do like this:
public interface IImageRecognitionEngine<TFoo0, TFoo1, TFoo2, TFoo3>
{
TFoo0 Learn(TFoo1 param);
TFoo2 Recognize(TFoo3 param);
}
public class FooImageRecognitionEngine : IImageRecognitionEngine<byte[], string, List<double>, string>
{
public byte[] Learn(string param)
{
throw new NotImplementedException();
}
public List<double> Recognize(string param)
{
throw new NotImplementedException();
}
}
But I would much more prefer generic methods instead of the whole interface. But I don't understand why I can do this:
public interface IImageRecognitionEngine2
{
TFoo0 Learn<TFoo0, TFoo1>(TFoo1 param);
TFoo2 Recognize<TFoo2, TFoo3>(TFoo3 param);
}
public class FooExampleClass
{
}
public class FooExampleClass2
{
}
public class Foo1ImageRecognitionEngine2 : IImageRecognitionEngine2
{
public FooExampleClass Learn<FooExampleClass, FooExampleClass2>(FooExampleClass2 param)
{
throw new NotImplementedException();
}
public FooExampleClass Recognize<FooExampleClass, FooExampleClass2>(FooExampleClass2 param)
{
throw new NotImplementedException();
}
}
But with primitive types the compiler gives me errors:
public class Foo2ImageRecognitionEngine2 : IImageRecognitionEngine2
{
public byte[] Learn<byte[], string>(string param)
{
throw new NotImplementedException();
}
public List<double> Recognize<List<double>, string>(string param)
{
throw new NotImplementedException();
}
}
I don't want to be able to chose what types to use when I instantiate an object of the class implementation. For example, I don't want to write an implementation like this:
public class Foo2ImageRecognitionEngine2 : IImageRecognitionEngine2
{
public TFoo0 Learn<TFoo0, TFoo1>(TFoo1 param)
{
throw new NotImplementedException();
}
public TFoo2 Recognize<TFoo2, TFoo3>(TFoo3 param)
{
throw new NotImplementedException();
}
}
And being able to do this:
var fooEngine = new Foo2ImageRecognitionEngine2();
fooEngine.Learn<string, int>(52);
And this doesn't work also:
public interface IImageRecognitionEngine3
{
object Learn(object param);
object Recognize(object param);
}
public class Foo1ImageRecognitionEngine3 : IImageRecognitionEngine3
{
public byte[] Learn(string param)
{
throw new NotImplementedException();
}
public List<double> Recognize(string param)
{
throw new NotImplementedException();
}
}
Thank you
public FooExampleClass Learn<FooExampleClass, FooExampleClass2>(FooExampleClass2 param)
{
throw new NotImplementedException();
}
does not do what you think - FooExampleClass and FooExampleClass2 are not types, but type parameters which can be instantiated to any class. This means a client could do:
var e = new Foo1ImageRecognitionEngine2();
e.Learn<string, object>(new object());
Your code only appears to work because it does nothing.
Generic methods like this have to work for any parameters the client chooses so there's no way to restrict the parameters to work for particular parameters. If you want to do that you need to move them to the interface definition which you have in your first example.
I have a scenario where I need the properties in my class to map to a dictionary. Here is a code sample:
public string Foo
{
get
{
if (!PropertyBag.ContainsKey("Foo"))
{
return null;
}
return PropertyBag["Foo"];
}
set
{
PropertyBag["Foo"] = value;
}
}
I have to apply this pattern to multiple properties. Is there a way to use attributes to do that?
I know that PostSharp would work for this purpose, but I was hoping there is a way to do it without using it.
This feels like a code smell to me. It would be better to use regular POCOs and convert them to a Dictionary only when needed.
public class BlogPost
{
public string Title { get; set; }
public string Body { get; set; }
public int AuthorId { get; set; }
public Dictionary<string, object> ToDictionary()
{
return this.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToDictionary(prop => prop.Name, prop => prop.GetValue(this, null));
}
}
Inspiration: How to convert class into Dictionary?
And to be honest, a ToDictionary method on your POCO's seems like a code smell. It would be better to refactor your code so the conversion of POCOs to Dictionaries happens in its own layer, as a service maybe.
Edit: This Gist I found while searching google for "c# convert object to dictionary" could provide a more generalized solution, and probably more bullet proof than my cobbled together example:
Gist: https://gist.github.com/jarrettmeyer/798667
From the Gist:
public static class ObjectToDictionaryHelper
{
public static IDictionary<string, object> ToDictionary(this object source)
{
return source.ToDictionary<object>();
}
public static IDictionary<string, T> ToDictionary<T>(this object source)
{
if (source == null)
ThrowExceptionWhenSourceArgumentIsNull();
var dictionary = new Dictionary<string, T>();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(source))
AddPropertyToDictionary<T>(property, source, dictionary);
return dictionary;
}
private static void AddPropertyToDictionary<T>(PropertyDescriptor property, object source, Dictionary<string, T> dictionary)
{
object value = property.GetValue(source);
if (IsOfType<T>(value))
dictionary.add(property.Name, (T)value);
}
private static bool IsOfType<T>(object value)
{
return value is T;
}
private static void ThrowExceptionWhenSourceArgumentIsNull()
{
throw new ArgumentNullException("source", "Unable to convert object to a dictionary. The source object is null.");
}
}
Credit: jerrettmeyer at GitHub
This should add a ToDictionary method to every object.
Edit: From the following comment
To give a bit of context, I am using Entity Framework and I have a class hierarchy that I would like to keep in one table while avoiding null columns everywhere.
Entity framework supports multiple table inheritance. That might be a better solution in your case.
You can write a GetValueOrDefault extension method and reduce the code a little.
public static class DictionaryExtensions
{
public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey,TValue> self, TKey key)
{
TValue value;
self.TryGetValue(key,out value);
return value;
}
}
public string Foo
{
get
{
return PropertyBag.GetValueOrDefault("Foo");
}
set
{
PropertyBag["Foo"] = value;
}
}
You can eliminate the magic strings using expressions.
If you're using at least .NET 4.5 then you have the CallerMemberNameAttribute which you could use like this:
class SomeClass
{
public string Foo
{
get
{
return GetPropertyValue();
}
set
{
SetPropertyValue( value );
}
}
private string GetPropertyValue( [CallerMemberName] string name = null )
{
string value;
PropertyBag.TryGetValue( name, out value );
return value;
}
private void SetPropertyValue( string value, [CallerMemberName] string name = null )
{
PropertyBag[name] = value;
}
}
This will result in the compiler filling out the name of the member for you. If you're not (or otherwise can't) use .NET 4.5, another alternative would be to take advantage of expression trees as suggested in another answer.
class Test
{
Dictionary<string,object> _values = new Dictionary<string, object>();
public string Foo
{
get
{
var value = GetValue();
return value == null ? string.Empty : (string)value;
}
set
{
SetValue(value);
}
}
private object GetValue()
{
var stack = new StackTrace();
var key = GetGenericName(stack.GetFrame(1).GetMethod().Name);
if (_values.ContainsKey(key)) return _values[key];
return null;
}
private void SetValue(object value)
{
var stack = new StackTrace();
var key = GetGenericName(stack.GetFrame(1).GetMethod().Name);
_values[key] = value;
}
private string GetGenericName(string key)
{
return key.Split('_')[1];
}
}
I'm trying to expose a read-only dictionary that holds objects with a read-only interface. Internally, the dictionary is write-able, and so are the objects within (see below example code). My problem is that IReadOnlyDictionary doesn't support covariant conversions because of the reason outlined in the question here. This means I can't just expose my internal dictionary as a read only one.
So my question is, is there an efficient way to convert my internal dictionary to an IReadOnlyDictionary, or some other way to handle this? The options I can think of are:
Hold two internal dictionaries and keep them in sync.
Create a new dictionary when the property is accessed and cast all the objects within.
Cast the IReadOnly's back to NotReadOnly when using it internally.
1 seems like a pain, 2 seems highly inefficient. 3 sounds like the most promising at the moment, but is still ugly. Do I have any other options?
public class ExposesReadOnly
{
private Dictionary<int, NotReadOnly> InternalDict { get; set; }
public IReadOnlyDictionary<int, IReadOnly> PublicList
{
get
{
// This doesn't work...
return this.InternalDict;
}
}
// This class can be modified internally, but I don't want
// to expose this functionality.
private class NotReadOnly : IReadOnly
{
public string Name { get; set; }
}
}
public interface IReadOnly
{
string Name { get; }
}
You could write your own read-only wrapper for the dictionary, e.g.:
public class ReadOnlyDictionaryWrapper<TKey, TValue, TReadOnlyValue> : IReadOnlyDictionary<TKey, TReadOnlyValue> where TValue : TReadOnlyValue
{
private IDictionary<TKey, TValue> _dictionary;
public ReadOnlyDictionaryWrapper(IDictionary<TKey, TValue> dictionary)
{
if (dictionary == null) throw new ArgumentNullException("dictionary");
_dictionary = dictionary;
}
public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); }
public IEnumerable<TKey> Keys { get { return _dictionary.Keys; } }
public bool TryGetValue(TKey key, out TReadOnlyValue value)
{
TValue v;
var result = _dictionary.TryGetValue(key, out v);
value = v;
return result;
}
public IEnumerable<TReadOnlyValue> Values { get { return _dictionary.Values.Cast<TReadOnlyValue>(); } }
public TReadOnlyValue this[TKey key] { get { return _dictionary[key]; } }
public int Count { get { return _dictionary.Count; } }
public IEnumerator<KeyValuePair<TKey, TReadOnlyValue>> GetEnumerator()
{
return _dictionary
.Select(x => new KeyValuePair<TKey, TReadOnlyValue>(x.Key, x.Value))
.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
I would suggest that you might want to define your own covariant interfaces, and include covariant access methods as well as a method which will create a read-only wrapper object which implements either IDictionary or IReadonlyDictionary with the desired types. Simply ignore IEnumerable<KeyValuePair<TKey,TValue>> within your interface.
Depending upon what you're doing, it may be helpful to define an IFetchByKey<out TValue> which is inherited by IFetchByKey<in TKey, out TValue>, with the former accepting queries for any type of object (given an object instance, a collection of Cat should be able to say whether it contains that instance, even if it's a type Dog or ToyotaPrius; the collection won't contain any instances of the latter types, and should be able to say so).
Maybe this solutions works for you:
public class ExposesReadOnly
{
private IDictionary<int, IReadOnly> InternalDict { get; set; }
public IReadOnlyDictionary<int, IReadOnly> PublicList
{
get
{
IReadOnlyDictionary<int, IReadOnly> dictionary = new ReadOnlyDictionary<int, IReadOnly>(InternalDict);
return dictionary;
}
}
private class NotReadOnly : IReadOnly
{
public string Name { get; set; }
}
public void AddSomeValue()
{
InternalDict = new Dictionary<int, NotReadOnly>();
InternalDict.Add(1, new NotReadOnly() { Name = "SomeValue" });
}
}
public interface IReadOnly
{
string Name { get; }
}
class Program
{
static void Main(string[] args)
{
ExposesReadOnly exposesReadOnly = new ExposesReadOnly();
exposesReadOnly.AddSomeValue();
Console.WriteLine(exposesReadOnly.PublicList[1].Name);
Console.ReadLine();
exposesReadOnly.PublicList[1].Name = "This is not possible!";
}
}
Hope this helps!
Greets
Depending on your use case, you might be able to get away with exposing a Func<int,IReadOnly>.
public class ExposesReadOnly
{
private Dictionary<int, NotReadOnly> InternalDict { get; set; }
public Func<int,IReadOnly> PublicDictionaryAccess
{
get
{
return (x)=>this.InternalDict[x];
}
}
// This class can be modified internally, but I don't want
// to expose this functionality.
private class NotReadOnly : IReadOnly
{
public string Name { get; set; }
}
}
public interface IReadOnly
{
string Name { get; }
}
Another approach for a specific lack of covariance:
A work around for a specific type of useful covariance on idictionary
public static class DictionaryExtensions
{
public static IReadOnlyDictionary<TKey, IEnumerable<TValue>> ToReadOnlyDictionary<TKey, TValue>(
this IDictionary<TKey, List<TValue>> toWrap)
{
var intermediate = toWrap.ToDictionary(a => a.Key, a =>a.Value!=null? a.Value.ToArray().AsEnumerable():null);
var wrapper = new ReadOnlyDictionary<TKey, IEnumerable<TValue>>(intermediate);
return wrapper;
}
}