C# force inherited class looping through list - c#

So for example I have two classes:
Class A
{
string property1;
string property2;
}
Class B : A
{
string property3;
string property4;
....
}
So B inherits class A's properties. They are sitting in a list, that is sitting in a dictionary
Dictionary <string, List<A>> myDictionary = new Dictionary<string, List<A>>();
List<A> myList = new List<A>();
There is one Dictionary, containing many List's, that all contain a mix of Class A & B objects.
While looping through, I am trying to access some properties from Class B objects, I have an if statement to find them but the program still thinks they are of type Class A and throws an error when I try and use a property3 or property4. For example:
string key = string key in dictionary;
string index = object position in list;
myDictionary[key][index].property3.someMethod();
Is there a way to tell the program that this is a class B object and allow the properties 3 & 4 to be used?

Cast the object safely as a B-type object, then check for null
var obj = myDictionary[key][index];
var bObj = obj as B;
if (bObj != null)
{
bObj.someMethod();
}
Although, I would also probably say it seems like your design is off. Ordinarily, I wouldn't expect something like this. Normally, if you're using inheritance, you'd want a design that allows them to be used interchangeably. For example, you might implement the behavior on A as a no-op, but override it on B to actually do something. This would make it so that consuming classes need not care whether the "A" thing is really an A or a B instance.

Related

C# dictionary lookup using derived class

I think this could be a common question but I failed to find any post about it.
I'm writing some pseudo code below. If you want to compile the code, please just ignore this post.
So say two classes: one base class and one child class. NOTE: both classes have override Equals() and GetHashCode() function to ensure equality with same property.
public class A // A has a string property of name
public class B:A // B has a string property of title
var a = new A{name = "bob"};
var b = new B{name = "bob", title = "em"};
Some code have a dictionary based on A
var dict = new Dictionary<A>();
Doing some adding stuff, for instance,
dict.Add(a);
However, the lookup function will raise KeyNotFoundException if i use a derived class searching with/o type cast
dict[b];
Dictionary will calculate the hashcode of B instead of A and raised the exception according to that.
A simple and awkward solution is to create a new instance of A based on B's property.
dict[new A{name = b.name}];
I wonder if there is any better solution?
Try creating an EqualityComparer, and pass an instance of it in the constructor of the dictionary.
class AEqualityComparer : IEqualityComparer<A>
{
public bool Equals(A x, A y)
{
return x.Equals(y);
}
public int GetHashCode(A obj)
{
return obj.GetHashCode();
}
}
var dict = new Dictionary<A, object>(new AEqualityComparer());
You're confusing storing objects in a list, with the key of a dictionary. If you use objects as a key, you need to supply a reference to the same object - not just one with the same properties.
If you do this:
dict.Add(new A{name = "bob"}, someData);
and then do this
var result = dict[new A{name = "bob"}];
you'll get 'key not found' because the two new As are different objects.

How to Ensure Immutability of a Generic

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")

How do I create a Dictionary of classes, so that I can use a key to determine which new class I want to initialize?

As per the question, how do I create a Dictionary in C# where the key is say, an integer, but the values are classes that I can call the constructor for by using just the value in the Dictionary? Each of the classes are derived from an abstract class, and they take the same parameters, so I feel like I should be able to store the resulting reference to the new class object in a variable of the abstract class type.
That being said, a Dictionary's value set is usually filled with references to objects, not types themselves. As a quick example, here's what I'm trying to do:
abstract class BaseObject {
int someInt;
}
class ObjectA : BaseObject {
ObjectA (int number) {
someInt = number;
}
}
class ObjectB : BaseObject {
ObjectB (int number) {
someInt = number;
}
}
And I want to be able to do the following:
Dictionary<int, ???????> objectTypes = new Dictionary<int, ???????>();
objectTypes.Add(0, ObjectA);
objectTypes.Add(1, ObjectB);
So I can eventually:
BaseObject newObjectA, newObjectB;
newObjectA = new objectTypes[0](1000);
newObjectB = new objectTypes[1](2000);
The syntax is probably quite different, but I hope I at least got across what I'm trying to accomplish.
Are you looking for something like this?
var objectTypes = new Dictionary<int, Func<int, BaseObject>>();
objectTypes[0] = input => new ObjectA(input);
objectTypes[1] = input => new ObjectB(input);
objectTypes[0](1000);
objectTypes[1](2000);
Here instead of storing object, I store a Func to generate each concrete object
Dictionary<int, Type> objectTypes = new Dictionary<int, Type>();
objectTypes.Add(0, typeof(ObjectA));
objectTypes.Add(1, typeof(ObjectB));
var newObjectA = (BaseObject)Activator.CreateInstance(objectTypes[0], new object[] {1000});
Documentation for Activator.CreateInstance
Leaving this here as it is just another way to do it, but Phuong's answer is a much cleaner and customizable approach at compile time.
The key difference is if you want something dynamic at runtime or compile time. If it's all compile time, I suggest the Func method. If your types are unknown at compile time, then you will want to use this way as there are many ways to dynamically instantiate a class using Activator.CreateInstance.

Check if two variables are of the same when the type is dynamic and both variables are the derivatives of same base class

Is it possible to check if the list contains an object of given (but dynamic) type, derrived from same basic abstract class?
The main problem is not about the list, but about comparing types itself.
In single variables and static variables, it's easy:
if(someVariable is int)
Checking the list with static type is also easy, like:
SomeList.OfType<int>().Any()
or
(from _Object in SomeList.OfType<int> where _Object is int select _Object).Count() == 0
but I cant't handle it if the type I want to check is dynamic, f.e. passed as method parameter:
abstract class BasicClass;
class DerivativeOne : BasicClass { }
class DerivativeTwo : BasicClass { }
// in main:
List<BasicClass> _List = new List<BasicClass>();
DerivativeOne a = new DerivativeOne();
DerivativeTwo b = new DerivativeTwo();
DerivativeOne c = new DerivativeOne();
if(!CheckIfTypeExistsInList(a, _List)
{
_List.Add(a);
}
if(!CheckIfTypeExistsInList(b, _List)
{
_List.Add(b);
}
if(!CheckIfTypeExistsInList(c, _List)
{
_List.Add(c); // this is what I don't want to happen,
// because I already have one object of type DerivativeOne in my list.
}
// the function:
bool CheckIfTypeExistsInList(BasicClass pObject, List<BasicClass> pList)
{
/// few attempts:
pList.OfType<(pObject.GetType()>().Any(); // attempt one, error
return (from _Object in SomeList.OfType<(pObject.GetType())> where _Object is int select _Object).Count() == 0; // attempt two, error
}
PS. I am aware that the code doesn't look neat, but I tried to show just the problem itself, skipping extra logic and stuff.
PS2. I am aware that the solution to the problem would be just to put some attribute to BasicClass and make each derivative to have unique value of the attribute, but still - I'm not looking for another route to solve the problem, I'm just interested if it's possible to do it "this" way.
When the type is known only at runtime, you cannot use it in a generic without using reflection. However, your task is simpler than that - you can use type equality to achieve the results that you want:
Type targetType = pObject.GetType();
if (SomeList.Any(o => targetType.Equals(o.GetType()))) {
...
}

C# new object but instead of copying an object, but referencing?

I have a class say ClassA with a string array inside class.
In my code I have ClassA as an object, then I want to create another new ClassA object, but it should copy the original object to the new class and do whatever it is supposed to do.
But strangely, when I declare that new object, whatever changed in the new object affects the original object.
Is there any reason why I am getting such behaviour?
It sounds like you're just doing this to copy it:
ClassA obj2 = obj1;
In this case then changes to obj2 would indeed be reflected in obj1 because the objects that you're using are just pointers to the same location in the memory heap. You're not actually copying it, you're just making another reference to it.
Take a look at the ICloneable interface here. You'd want something like this:
public class ClassA : ICloneable
{
public string myString { get; set; }
public object Clone()
{
var obj = new ClassA();
obj.myString = myString;
return myObj;
}
}
Then you'd call it like this:
ClassA obj2 = (ClassA)obj1.Clone();
Keep in mind that this isn't very type-safe, however. That cast is a bit messy (and, honestly, I haven't tried it, so it might even be problematic). I don't think .NET has introduced a generic ICloneable yet. But it shouldn't be too hard to write one. Something like:
public interface ICloneable<T>
{
public T Clone();
}
public class ClassA : ICloneable<ClassA>
{
public string myString { get; set; }
public ClassA Clone()
{
var obj = new ClassA();
obj.myString = myString;
return myObj;
}
}
This should be callable like this:
ClassA obj2 = obj1.Clone<ClassA>();
or possibly even (at least with a little tweaking):
ClassA obj2 = obj1.Clone();
An additional benefit to making a generic interface like this is that any given class can be "cloneable" to other types, not just itself. You can implement as many ICloneable<T> interfaces as you want on a single class. So you could have something like:
SomeOtherClass obj3 = obj1.Clone<SomeOtherClass>();
This is all off the top of my head and I don't have a compiler handy to test it, but you get the idea.
I'm sure it is because you are just setting another reference to the one string array in the new object. If you want a separate string array you need to create a constructor that creates a new string array and copies the strings over.
You can make a constructor overload that takes a new ClassA object and copies it's parameters.
public class ClassA
{
public String SomeParam { get; set; }
public ClassA(ClassA myoldobject)
{
//Logic for initializing new object.
this.SomeParam = myoldobject.SomeParam;
}
public ClassA(String someparam)
{
this.SomeParam = someparam;
}
}
This enables you to say
ClassA one = new ClassA("Test");
ClassA two = new ClassA(one);
This is because class - is a reference type and you are trying to get the behaviour of a value type. See deeper explanation here. Also it is greatly explained in CLR via C# book by J. Richter.
If you want to copy a reference type, you might need to implement an IClonable interface and call Clone for that.
It seems that you've assigned the first object to the second ..
To copy an existed object you have to assign all of its properties values to the new object, not to assign the whole object because this way you create another reference to the same object.
To create a copy of the first instance of ClassA, try the following:
ClassA = secondObject = new ClassA();
secondObject.Property1 = firstObject.Property1;
secondObject.Property2 = firstObject.Property2;
............

Categories

Resources