I was doing some work with interfaces today, when I run into the following scenario. Given these two simple interfaces:
public interface IItem { }
public interface IInventory
{
ICollection<IItem> Items { get; }
}
I made a simple class to implement IInventory, and noticed that this implementation is perfectly fine as written:
public class BasicInventory1 : IInventory
{
private Dictionary<int, IItem> items;
public ICollection<IItem> Items
{
get { return items.Values; }
}
}
But yet, this implementation requires a cast:
public class BasicInventory2 : IInventory
{
private Dictionary<int, IItem> items;
public ICollection<IItem> Items
{
get { return (ICollection<IItem>)items; }
}
}
Why does one require a cast and the other doesn't? Checking the object typing for both collections that are getting returned in either case confirms that they both in fact implement ICollection.
I suspect there is some magic type conversions going on under the hood here, and therefore seems to have something to do with co/contravariance, but I don't quite see what exactly is going on.
Dictionary<int, IItem> does not implement ICollection<IItem>. Simple as that.
It wouldn't make sense to implement that interface because you cannot add to a dictionary without specifying a key. The interface does not make sense.
This is a runtime error because items could refer to a subclass of Dictionary so that the cast might be valid.
I think that if you were to add .Values to the second example, you would not need the cast
public class BasicInventory2 : IInventory
{
private Dictionary<int, IItem> items;
public ICollection<IItem> Items
{
get { return items.Values; }
}
}
This is because items is a Dictionary and that implements ICollection<KeyValuePair<TKey, TValue>>.
This code is NOT VALID and will always generate a runtime error:
public class BasicInventory2 : IInventory
{
private Dictionary<int, IItem> items = new Dictionary<int, IItem>();
public ICollection<IItem> Items
{
get
{
return (ICollection<IItem>) items;
}
}
}
A Dictionary<int, IItem> does NOT implement ICollection<IItem>, whereas the type returned from Dictionary<int, IItem>.Values does.
So the answer is:
The first case is ok because Values is of the correct type.
In the second case, the compiler knows that you are trying to return the wrong type and so it gives you a compile error.
If you override the error with a case, you will get a runtime BadCastException.
In BasicInventory1 you return items.Values in BasicInventory2 you return only items.
.Values returns a ICollection, so no cast is need.
MSDN:
Dictonary
Values
In the second code you use the dictionary as return value where in the first code you use the values. Dictionary<int,IItems> inherits from ICollection<KeyValuePair<int,IItems>> thus is not ICollection<IItems>. Therefore you need the cast.
Related
This example is in C# but the question really applies to any OO language. I'd like to create a generic, immutable class which implements IReadOnlyList. Additionally, this class should have an underlying generic IList which is unable to be modified. Initially, the class was written as follows:
public class Datum<T> : IReadOnlyList<T>
{
private IList<T> objects;
public int Count
{
get;
private set;
}
public T this[int i]
{
get
{
return objects[i];
}
private set
{
this.objects[i] = value;
}
}
public Datum(IList<T> obj)
{
this.objects = obj;
this.Count = obj.Count;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return this.objects.GetEnumerator();
}
}
However, this isn't immutable. As you can likely tell, changing the initial IList 'obj' changes Datum's 'objects'.
static void Main(string[] args)
{
List<object> list = new List<object>();
list.Add("one");
Datum<object> datum = new Datum<object>(list);
list[0] = "two";
Console.WriteLine(datum[0]);
}
This writes "two" to the console. As the point of Datum is immutability, that's not okay. In order to resolve this, I've rewritten the constructor of Datum:
public Datum(IList<T> obj)
{
this.objects = new List<T>();
foreach(T t in obj)
{
this.objects.Add(t);
}
this.Count = obj.Count;
}
Given the same test as before, "one" appears on the console. Great. But, what if Datum contains a collection of non-immutable collection and one of the non-immutable collections is modified?
static void Main(string[] args)
{
List<object> list = new List<object>();
List<List<object>> containingList = new List<List<object>>();
list.Add("one");
containingList.Add(list);
Datum<List<object>> d = new Datum<List<object>>(containingList);
list[0] = "two";
Console.WriteLine(d[0][0]);
}
And, as expected, "two" is printed out on the console. So, my question is, how do I make this class truly immutable?
You can't. Or rather, you don't want to, because the ways of doing it are so bad. Here are a few:
1. struct-only
Add where T : struct to your Datum<T> class. structs are usually immutable, but if it contains mutable class instances, it can still be modified (thanks Servy). The major downside is that all classes are out, even immutable ones like string and any immutable class you make.
var e = new ExtraEvilStruct();
e.Mutable = new Mutable { MyVal = 1 };
Datum<ExtraEvilStruct> datum = new Datum<ExtraEvilStruct>(new[] { e });
e.Mutable.MyVal = 2;
Console.WriteLine(datum[0].Mutable.MyVal); // 2
2. Create an interface
Create a marker interface and implement it on any immutable types you create. The major downside is that all built-in types are out. And you don't really know if classes implementing this are truly immutable.
public interface IImmutable
{
// this space intentionally left blank, except for this comment
}
public class Datum<T> : IReadOnlyList<T> where T : IImmutable
3. Serialize!
If you serialize and deserialize the objects that you are passed (e.g. with Json.NET), you can create completely-separate copies of them. Upside: works with many built-in and custom types you might want to put here. Downside: requires extra time and memory to create the read-only list, and requires that your objects are serializable without losing anything important. Expect any links to objects outside of your list to be destroyed.
public Datum(IList<T> obj)
{
this.objects =
JsonConvert.DeserializeObject<IList<T>>(JsonConvert.SerializeObject(obj));
this.Count = obj.Count;
}
I would suggest that you simply document Datum<T> to say that the class should only be used to store immutable types. This sort of unenforced implicit requirement exists in other types (e.g. Dictionary expects that TKey implements GetHashCode and Equals in the expected way, including immutability), because it's too difficult for it to not be that way.
Kind of hacky, and definitely more confusing than it's worth in my opinion, but if your T is guaranteed to be serializable, you can store string representations of the objects in your collection rather than storing the objects themselves. Then even if someone pulls an item from your collection and modifies it, your collection would still be intact.
It would be slow and you'd get a different object every time you pulled it from the list. So I'm not recommending this.
Something like:
public class Datum<T> : IReadOnlyList<T>
{
private IList<string> objects;
public T this[int i] {
get { return JsonConvert.DeserializeObject<T>(objects[i]); }
private set { this.objects[i] = JsonConvert.SerializeObject(value); }
}
public Datum(IList<T> obj) {
this.objects = new List<string>();
foreach (T t in obj) {
this.objects.Add(JsonConvert.SerializeObject(t));
}
this.Count = obj.Count;
}
public IEnumerator<T> GetEnumerator() {
return this.objects.Select(JsonConvert.DeserializeObject<T>).GetEnumerator();
}
}
It's impossible. There's no possible way to constrain the generic type to be immutable. The best that you can possibly do is write a collection that cannot allow the structure of that collection to be modified. There is no way to prevent the collection from being used as a collection of some mutable type.
think that such collections are not match OOP, because this design leads to specific co-relation between independent classes - collection and it's items. How one class can change behavior of other without knowlege of each other?
So suggestions of serialization and so can allow you to do it on hacky way, but better is to decide if it's so required to make collection of immutable items, who trys to change them except your own code? May be better "to not mutate" items rather than try "make them immutable".
I faced the same problem, where I implement an object (say CachedData<T>) which handles a cached copy of the property of another object (say T SourceData). When calling the constructor of CachedData, you pass a delegate which returns a SourceData. When calling CachedData<T>.value, you get a copy of SourceData, which is updated every now and then.
It would make no sense to try caching an object, as .Value would only cache the reference to the data, not the data itself. It would only make sense to cache data types, strings, and perhaps structures.
So I ended up:
Thoroughly documenting CachedData<T>, and
Throwing an error in the constructor if T is neither a ValueType, a Structure, or a String. Some like (forgive my VB): If GetType(T) <> GetType(String) AndAlso GetType(T).IsClass Then Throw New ArgumentException("Explain")
I noticed something strange and there is a possibility I am wrong.
I have an interface IA and class A:
interface IA { .... }
class A : IA { .... }
In other class I have this:
private IList<A> AList;
public IList<IA> {
get { return AList; }
}
But I get compilation error.
But if I change it to:
public IList<IA> {
get { return AList.ToArray(); }
}
Everything is fine.
Why is it?
Why this doesn't work
private IList<A> AList;
public IList<IA> { get { return AList; } }
Exposing the property as IList<IA> would allow you to try to add class B : IA to the list, but the underlying list is really IList<A>, B is not A, so this would blow up in your face. Thus, it is not allowed.
Why this works:
public IList<IA> { get { return AList.ToArray(); } }
Array variance is broken. You can return the list as an array, it will still blow up in your face at runtime if you tried an Add operation (or try to replace an object at a given index with something other than an object of type A, but it's legal at compile time. A different example of this variance at play:
string[] array = new string[10];
object[] objs = array; // legal
objs[0] = new Foo(); // will bite you at runtime
From comments:
So what you suggest to use? How can I make the property return valid
object? How can I make the return value read only?
If consumers only need to iterate over the sequence and not have random, indexed access to it, you can expose the property as an IEnumerable<IA>.
public IEnumerable<IA> TheList
{
get { return AList.Select(a => a); }
}
(The Select is actually not technically needed, but using this will prevent consumers from being able to cast the result to its true underlying List<> type.) If the consumers decide they want a list or an array, they are free to call ToList() or ToArray() on it, and whatever they do with it (in terms of adding, removing, replacing items) will not affect your list. (Changes to the items' properties would be visible.) Similarly, you could also expose the collection an IList<IA> yourself in a safe way
public IList<IA> TheList
{
get { return AList.ToList<IA>(); }
}
Again, this would return a copy of the list, so any changes to it would not affect your underlying list.
Because native arrays are broken. This code is bad, you shouldn't do it, and the C# designers wish desperately they could undo it.
Arrays are covariant but lists are not.
I want to add an item to a Generic list using reflection. In the method "DoSomething", I am trying to finish the following line,
pi.PropertyType.GetMethod("Add").Invoke(??????)
but I am getting different kinds of error.
Below is my complete code
public class MyBaseClass
{
public int VechicleId { get; set; }
}
public class Car:MyBaseClass
{
public string Make { get; set; }
}
public class Bike : MyBaseClass
{
public int CC { get; set; }
}
public class Main
{
public string AgencyName { get; set; }
public MyBaseCollection<Car> lstCar {get;set;}
public void DoSomething()
{
PropertyInfo[] p =this.GetType().GetProperties();
foreach (PropertyInfo pi in p)
{
if (pi.PropertyType.Name.Contains("MyBaseCollection"))
{
//Cln contains List<Car>
IEnumerable<MyBaseClass> cln = pi.GetValue(this, null) as IEnumerable<MyBaseClass>;
**//Now using reflection i want to add a new car to my object this.MyBaseCollection**
pi.PropertyType.GetMethod("Add").Invoke(??????)
}
}
}
}
Any ideas / suggestion ?
I think you want:
// Cast to IEnumerable<MyBaseClass> isn't helping you, so why bother?
object cln = pi.GetValue(this, null);
// Create myBaseClassInstance.
// (How will you do this though, if you don't know the element-type?)
MyBaseClass myBaseClassInstance = ...
// Invoke Add method on 'cln', passing 'myBaseClassInstance' as the only argument.
pi.PropertyType.GetMethod("Add").Invoke(cln, new[] { myBaseClassInstance } );
Since you don't know what the element-type of the collection is going to be (could be Car, Bike, Cycle etc.) you're going to find it hard to find a useful cast. For example, although you say the collection will definitely implement IList<SomeMyBaseClassSubType>, that isn't all that helpful since IList<T> isn't covariant. Of course, casting to IEnumerable<MyBaseClass> should succeed, but that won't help you since it doesn't support mutations. On the other hand, if your collection-type implemented the non-generic IList or ICollection types, casting to those might come in handy.
But if you're sure that the collection will implement IList<Car> (i.e. you know the element-type of the collection beforehand), things are easier:
// A much more useful cast.
IList<Car> cln = (IList<Car>)pi.GetValue(this, null);
// Create car.
Car car = ...
// The cast helped!
cln.Add(car);
As an alternative... Just don't; consider the non-generic IList interface:
IList list = (IList) {... get value ...}
list.Add(newItem);
While it isn't obligatory for all generic collections to implement IList, they pretty much all do, since it underpins such a lot of core framework code.
start with typeof<List<>>.GetMethods, you do not invoke a method of the property, but a method of the type of the property
Could you just avoid reflection all together and use:
List<MyBaseClass> lstCar { get; set; }
lstCar.Add((MyBaseClass)new Car());
You could also consider using an interface or abstract methods...
Let's say I have the following classes that have different implementations based on the object to be stored in:
public class ListOfPersistent<T> :
IList<T> where T : Persistent {... implementation ...}
public class ListOfNonPersistent<T> :
IList<T> {... implementation ...}
And I want to use one of another version on the above classes by doing something like this:
public class PersistentList<T> : IList<T> {
protected PersistentList() {
if (list != null) {
return;
}
if (Extensions.IsPersistent<T>()) {
list = new ListOfPersistent<T>();
} else {
list = new ListOfNonPersistent<T>();
}
}
protected IList<T> list;
....
}
Of course the above does not compiles, because there is a type constrain on the first class and none on the second. Is there any way I can: Tell the compiler that it should not check the constrain on this specific case (list = new ListOfPersistent<T>()) because I KNOW it will be of that type, or do some covariance/contravariance magic so the code compiles without any issues?
Covariance and contravariance won’t help you here because IList<T> is invariant.
Personally I would argue that you have a flaw in your class design. You shouldn’t want to instantiate a ListOfPersistent<T> and then place it in a variable whose type, IList<T>, is incompatible. Unfortunately I cannot suggest a good alternative because I have no idea how you are planning to use these classes or what your overall goal is; but I can make a suggestion with a disclaimer that it is hacky and should probably only be used if you really know what you are doing:
public static class ListUtils
{
public static object CreateListOfPersistent(Type elementType)
{
if (!typeof(Persistent).IsAssignableFrom(elementType))
throw new ArgumentException("elementType must derive from Persistent.", "elementType");
var listType = typeof(ListOfPersistent<>).MakeGenericType(elementType);
return Activator.CreateInstance(listType);
}
}
// ...
if (Extensions.IsPersistent<T>())
list = (IList<T>) ListUtils.CreateListOfPersistent(typeof(T));
else
list = new ListOfNonPersistent<T>();
I'd like to have a class "A" with a (for example) SortedList collection "SrtdLst" property, and inside this class "A" allow the addition or subtraction of "SrtdLst" items. But in a instance of the class "A", only allow to get or set the content of the items, not to add new items or subtract the existing ones. In code:
class A
{
public SortedList<string, string> SrtdLst = new SortedList<string, string>();
public A()
{
// This must work:
SrtdLst.Add("KeyA", "ValueA");
// This too:
SrtdLst["KeyA"] = "ValueAAA";
}
}
class B
{
public A a = new A();
public B()
{
// I want the following code to fail:
a.SrtdLst.Add("KeyB", "ValueB");
// But this must work:
a.SrtdLst["KeyA"] = "ValueBBB";
}
}
UPDATE: I want to create a class like System.Data.SqlClient.SqlCommand. For the Stored Procedures you can use the member "DeriveParameters" that fills a collection of "Parameters", so only the value of each item can be modified.
How can this be done?
If you want to ban the modifying operations at compile time, you need a type-safe solution.
Declare an interface for the publicly allowed operations. Use that interface as the property type.
public interface IReadOnlyList<T>
{
T this[int index] { get; }
int Count { get; }
}
Then declare a class that implements that interface and inherits from the standard collection class.
public class SafeList<T> : List<T>, IReadOnlyList<T> { }
Assuming you get the interface definition right, you won't need to implement anything by hand, as the base class already provides the implementations.
Use that derived class as the type of the field that stores the property value.
public class A
{
private SafeList<string> _list = new SafeList<string>();
public IReadOnlyList<string>
{
get { return _list; }
}
}
Within class A, you can use _list directly, and so modify the contents. Clients of class A will only be able to use the subset of operations available via IReadOnlyList<T>.
For your example, you're using SortedList instead of List, so the interface probably needs to be
public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
V this[K index] { get; }
}
I've made it inherit IEnumerable as well, which is readonly anyway, so is perfectly safe. The safe class would then be:
public class SafeSortedList<K, V> : SortedList<K, V>, IReadOnlyDictionary<K, V> { }
But otherwise it's the same idea.
Update: just noticed that (for some reason I can't fathom) you don't want to ban modifying operations - you just want to ban SOME modifying operations. Very strange, but it's still the same solution. Whatever operations you want to allow, "open them up" in the interface:
public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
V this[K index] { get; set; }
}
Of course, that's the wrong name for the interface now... why on earth would you want to ban adding via Add but not ban it via the indexer? (The indexer can be used to add items, just as the Add method can.)
Update
From your comment I think you mean that you want to allow assignment to the value of an existing key/value pair, but disallow assignment to a previously unknown key. Obviously as keys are specified at runtime by strings, there's no way to catch that at compile time. So you may as well go for runtime checking:
public class FixedSizeDictionaryWrapper<TKey, TValue> : IDictionary<TKey, TValue>
{
IDictionary<TKey, TValue> _realDictionary;
public FixedSizeDictionaryWrapper(IDictionary<TKey, TValue> realDictionary)
{
_realDictionary = realDictionary;
}
public TValue this[TKey key]
{
get { return _realDictionary[key]; }
set
{
if (!_realDictionary.Contains(key))
throw new InvalidOperationException();
_realDictionary[key] = value;
}
}
// Implement Add so it always throws InvalidOperationException
// implement all other dictionary methods to forward onto _realDictionary
}
Any time you have an ordinary dictionary and you want to hand it to some method that you don't trust to update the existing values, wrap it in one of these.
EDIT: Original answer is below. As earwicker points out, I hadn't noticed that you aren't asking for it to be readonly - just to prevent the Add operation. That doesn't sound like a good idea to me, as the only difference between Add and the indexer-setter is that Add throws an exception if the element is already present. That could easily be faked up by the caller anyway.
Why do you want to restrict just that one operation?
Original answer
For one thing, don't use public fields. That's a surefire way to run into problems.
It looks like you want a read-only wrapper class round an arbitrary IDictionary. You can then have a public property which returns the wrapper, while you access the private variable from within your class. For example:
class A
{
private SortedList<string, string> sortedList = new SortedList<string, string>();
public IDictionary<string, string> SortedList
{
get { return new ReadOnlyDictionaryWrapper(sortedList);
}
public A()
{
sortedList.Add("KeyA", "ValueA");
sortedList["KeyA"] = "ValueAAA";
}
}
Now you've just got to find a ReadOnlyDictionary implementation... I can't implement it right now, but I'll be back later if necessary...
Just make the list private, and expose it as an indexer:
class A {
private SortedList<string, string> _list;
public A() {
_list = new SortedList<string, string>()
}
public string this[string key] {
get {
return _list[key];
}
set {
_list[key] = value;
}
}
}
Now you can only access the items using the index:
a["KeyA"] = "ValueBBB";
However, as the indexer of the list allows creation of new items, you would have to add code in the indexer to prevent that if you don't want that do be possible.
If the keys are known outside of the class then you can add a ChangeItem(key, newValue) and ReadItem(key) to your wrapper class. Then keep the SortedList private to the class.