My code has 3 classes (a, b, c), that (b,c) classes inherit a. and I have a list (list mylist). My prblem is about adding to element from class b or class c
public class A
{
public int x;
public int y;
public A(int x, int y)
{
this.x = x;
this.y = y;
}
}
public class B : A
{
public int z;
public B(int x, int y, int z) : base(x, y)
{
}
}
class Program
{
static void Main(string[] args)
{
var myA = new List<A>();
myA.Add(new A(1, 2));
myA.Add(new B(3, 4, 5));
Console.WriteLine(myA[1]);
Console.WriteLine("0.x=" + myA[0].x + "--0.y=" + myA[0].y);
Console.WriteLine("1.x=" + myA[1].x + "--1.y=" + myA[1].y + "--1.z=");// I can't see myA.z
}
}
I've removed my former answer since you updated the question a lot.
The reason you don't see the property is because (as mentioned in a comment), the list only contains a "contract" to contain instances of the class A. Even if it also containes derrived classes (such as class B), it still isn't valid to access properties of B, because we can only ever be "certain" that the elements inside the list contain at least all the behavior and properties of A.
This is by design to ensure that we can't accidentally try accessing a property which doesn't exist for an instance of A during runtime.
Related
I have these classes
class Start
{
public List<Base> list { get; set; }
public Start()
{
list = new List<Base>();
}
}
public abstract class Base
{
public int a { get; set; }
}
class B : Base
{
public int b;
public B(int a, int b) { this.a = a; this.b = b; }
}
class C : Base
{
public int c;
public C(int a, int c) { this.a = a; this.c = c; }
}
I want list property of class Start to hold instances of class B or instances of class C (not both together, but it may hold the same type of any of B or C)
If possible, I don't want to use Generics
In C#, This is possible:
List<Object> lst = new List<Object>();
lst.Add(1);
list.Add("Text");
Console.WriteLine("{0} {1}", lst[0], lst[1]);
I don't understand why I can't make a similar behavior here:
Start s = new Start();
B b = new B(1, 2);
s.list.Add(b);
Console.WriteLine(s.list[0].a); //works
Console.WriteLine(s.list[0].b); //doesn't work
The difference between the two snippets is that in the first one you are not accessing any type-specific information (fields/properties/methods), i.e. something like the following will not compile too:
List<Object> lst = new List<Object>();
lst.Add(1);
list.Add("Text");
// will not compile despite string having Length property:
Console.WriteLine("{0} {1}", lst[0], lst[1].Length);
a is common property declared in Base class, so it is available for every child of Base, if you want to access child specific properties you need to type test/cast :
Start s = new Start();
B b = new B(1, 2);
s.list.Add(b);
Console.WriteLine(s.list[0].a); //works
if(s.list[0] is B b)
{
Console.WriteLine(b.b);
}
or make Start generic:
class Start<T> where T: Base
{
public List<T> list { get; set; }
public Start()
{
list = new List<T>();
}
}
var s = new Start<B>();
s.list.Add(new B(1, 2));
Console.WriteLine(s.list[0].b);
P.S.
Note that overriding ToString in Base, B and A will make Console.WriteLine("{0}", s.list[0]); "work":
class B : Base
{
// ...
public override string ToString() => return $"B(A: {a} B: {b})";
}
class C : Base
{
// ...
public override string ToString() => return $"C(A: {a} B: {c})";
}
Start s = new Start();
B b = new B(1, 2);
s.list.Add(b);
s.list.Add(new C(4, 2));
Console.WriteLine("{0} {1}", s.list[0], s.list[1]); // prints "B(A: 1 B: 2) C(A: 4 B: 2)"
So possibly you can introduce some method in Base which will allow you to use List<Base> (hard to tell without knowing actual use case).
The List<Object> example is possible because both int and string inherit from Object, which provides a ToString() method that is called implicitly on the line that writes the output. That is, no members of either the int or string types are used in that example that are specific to their own types.
You might accomplish what you need without generics by adding an interface that both B and C can implement, since both the b and c properties are compatible (they are both ints). However, this is clearly a contrived example, and I expect the real code is more complicated. In that case, generics are likely your best option.
because all Base objects dont have 'b' fields
you need to test to see if list[0] is an instance of 'B' and then cast it to a B
if (list[0] is B )
{
Console.WriteLine(((B)(list[0]).b);
}
Based on the comments underneath the question, perhaps a combination of both a non-generic interface and a generic Start class could work in this scenario.
The non-generic base interface for the generic Start class would declare a get-only List property as IReadOnlyList<Base>. IReadOnlyList is co-variant, allowing to return different List<T> instances where T is a concrete derived type from Base.
public interface IStart
{
IReadOnlyList<Base> List { get; }
}
The generic Start<TBase> class implements IStart, puts the IStart.List property in an explicit interface declaration and declares its own List property that is typed as List<TBase>.
public class Start<TBase> : IStart where TBase : Base
{
public List<TBase> List { get; set; }
IReadOnlyList<Base> IStart.List => this.List;
public Start()
{
List = new List<TBase>();
}
}
Note that both the explicit interface implementation of IStart.List and Start<TBase>'s own List property return the same List<TBase> instance.
This setup makes the following things possible (or impossible, see the code comments):
var startC = new Start<C>();
startC.List.Add(new C()); // this works, of course it works
startC.List.Add(new B()); // The compiler will NOT allow this
IStart SomeMethodProducingAStart()
{
if (someCondition)
return new Start<B>();
else
return new Start<C>();
}
void SomeMethodConsumingAStart(IStart start)
{
if (start is Start<B> startWithBs)
{
// do stuff with startWithBs...
Console.WriteLine(startWithBs.List[0].a);
Console.WriteLine(startWithBs.List[0].b);
}
else if (start is Start<C> startWithCs)
{
// do stuff with startWithCs...
Console.WriteLine(startWithCs.List[0].a);
Console.WriteLine(startWithCs.List[0].c);
}
// if you don't care about the members specific to either B or C,
// just do this
Console.WriteLine(start.List[0].a);
// since start can be any Start<T>
// the following is denied by the compiler
// simply by virtue of IStart.List being an IReadOnlyList
start.List.Add(new C()); // no can do!
}
Whether this approach fits your application scenario well is for you to determine, but it's an approach that tries to avoid granular pattern matching on individual list items and aims at simplifying working with Start instances once they have been pattern-matched/cast to the correct Start<TBase> type.
I'm working on a test for an interview and need to write a few classes that are then tested with Assert statements. There is one part where two objects are tested with Assert.AreEqual() immediately followed by a test with Assert.AreNotSame for the same two objects. My understanding is that the first test checks that two objects have the same values (a and b in my example) and the second test checks that they point two different objects in memory. However, the first Assert fails both in my example and in the program. Am I missing something about how those two Assert tests should work? How can they both pass?
public class Foo
{
public int a { get; set; }
public int b { get; set; }
public Foo(int a, int b) { this.a = a; this.b = b; }
}
Foo a = new Foo();
a.a = 1;
a.b = 2;
Foo b = new Foo(1, 2);
Assert.AreEqual(a,b);//this fails
Assert.AreNotSame(a,b);
Both objects are not equal and not same since it is two different instances of the object.
If you override Equals method on the object than you can implement it in a way that you check if the properties of both objects are equal. If they are than the object is also equal. So your new class should look like this...
public class Foo
{
public int a { get; set; }
public int b { get; set; }
public Foo(int a, int b) { this.a = a; this.b = b; }
public override bool Equals(object obj)
{
return ((Foo)obj).a == this.a && ((Foo)obj).b == this.b;
}
}
Also check this SO answer for further clarification...
If I want to use objects of this class as keys in a Dictionary, what do I need to do? (10.0, 20.0) shouldn't exist as a key twice.
public class IntPoint
{
public Int64 X { get; set; }
public Int64 Y { get; set; }
public IntPoint(Int64 X, Int64 Y)
{
this.X = X; this.Y = Y;
}
public override int GetHashCode()
{
return X.GetHashCode() ^ Y.GetHashCode();
}
}
EDIT
public static Dictionary<IntPoint, List<int>> GetPolygonDuplicateIndixes(Polygon p)
{
Dictionary<IntPoint, List<int>> d = new Dictionary<IntPoint, List<int>>();
int i = 0;
foreach(IntPoint point in p)
{
if(!d.ContainsKey(point))
{
d[point] = new List<int>();
}
d[point].Add(i);
i++;
}
...
I'm getting duplicates in d. Why? 22002, 1501 occurs twice in p.
If you look at the Dictionary documentation, you'll see that if the keys implement
IEquatable, that equality implementation will be used instead.
The following link from MSDN recommends using combining X and Y using an XOR operation
http://msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx#Y1500
public override int GetHashCode() {
return X ^ Y;
}
The thing to remember is that
It is important that the hash computation is fast
If two objects are equal then there hash mush be equal, but two objects with the same hash do not necessarily have to be equal
Your GetHashCode can look like:
public override int GetHashCode()
{
return X.GetHashCode() ^ Y.GetHashCode();
}
But you still need to override Equals and implement IEquatable interface.
You may also use Tuple<Int64, Int64> instead of your own IntPoint class (if you're on .NET 4.0).
I have a dummy class where I am testing arrays. I've noticed that when I want to dynamically allocate size of array at runtime, fields that indicate this size have to be static. I know I should probably use collections for this kind of code, but I'm more interested why do these fields have to be static? Is there any particular reason behind this?
class Foo
{
private static int x;
private static int y;
private int[,] bar = new int[ x, y ];
public Foo( int a, int b )
{
x = a;
y = b;
}
}
They don't really have to be static - it's just that you can't refer to other instance variables within instance variable initializers. In other words, it's a bit like this:
class Foo
{
private int x;
private int y = x; // Invalid
}
From section 10.5.5.2 of the C# 3 spec:
A variable initializer for an instance
field cannot reference the instance
being created. Thus, it is a
compile-time error to reference this
in a variable initializer, as it is a
compile-time error for a variable
initializer to reference any instance
member through a simple-name.
I suspect you really want something like this:
class Foo
{
private int x;
private int y;
private int[,] bar;
public Foo( int a, int b )
{
x = a;
y = b;
bar = new int[x, y];
}
}
Of course you don't really need x and y at all - they're just convenient to keep each dimension of the array. You could also use bar.GetLength(0) and bar.GetLength(1) to get the two lengths, but that's not terribly pleasant.
You might want to rename x and y to width and height though, or something similar :)
The example shown of 'Foo will never have the array 'bar be anything but an an array of size [0,0] : it's instantiation occurs before you call the class constructor.
Try this :
public class Foo2
{
private int[,] bar;
public Foo2(int a, int b)
{
bar = new int[a,b];
}
}
That will give you an array of size [a,b] without use of 'static.
I want to update an instance with properties of a newly created object at once but not breaking the instance binding to other variables. For eg.
public class MyClass{
public double X;
public double Y;
}
MyClass a = new MyClass(2,1);
MyClass b = a;
MyClass c = new MyClass(1,1);
a = c; //'b' should also be equal to 'a'.
//I dont want to do something like this:
a.Y = c.Y;
a.X = c.X;
In my code, 'b' is actually not accessible anymore because it is binded to some UI, 'a' is my only way through updating 'b'. So after 'a = c' is called, b should have the location of [1,1].
Experimental : please feel free to "blow this out of the water" :) Tested in VS 2010 beta 2 against FrameWork 4.0 and 3.5 (full, not "client" versions).
private class indirectReference
{
// using internal so Loc is not visible outside the class
internal struct Loc
{
public double X;
public double Y;
}
// publicly exposed access to the internal struct
public Loc pairODoubles;
// ctor
public indirectReference(double x, double y)
{
pairODoubles.X = x;
pairODoubles.Y = y;
}
}
// test ...
indirectReference r1 = new indirectReference(33, 33);
indirectReference r2 = r1;
indirectReference r3 = new indirectReference(66, 66);
// in this case the doubles in r2 are updated
r1.pairODoubles = r3.pairODoubles;
You could do something like this:
class Wrapper
{
public Wrapper(Location l)
{
this.L = l;
}
public Location L;
}
Wrapper a = new Wrapper(new Location(2,1));
Wrapper b = a;
Location c = new Location(1,1);
a.L = c;
I'm not sure whether it's really appropriate without more context. Just add a level of indirection.
Don't you think making the MyClass immutable would be a suitable approach?
Or: you should perform some reference counting, through a wrapper.