I have the following three classes
public class Base
{
string name;
}
public class Foo : Base
{
int value;
}
public class Bar : Base
{
double value;
}
This is what I'm attempting
Base current = null;
if (somecondition)
current = new Foo();
else
current = new Bar();
for (int i=0; i<5; i++)
{
current.value = i;
}
The problem is VS 2010 shows an error in the loop body because Base doesn't have a property value.
Now, I could workaround this issue by this way:
Base current = null;
bool isBar = true;
if (somecondition)
{
current = new Foo();
isBar = false;
}
else
current = new Bar();
for (int i=0; i<5; i++)
{
if (isBar)
(current as Bar).value = i;
else
(current as Foo).value = i;
}
But I was hoping for a better solution because once the loop starts iterating, the type of current isn't going to change, yet I am going to test the type and accordingly cast it for each iteration.
What would be the right way to do this?
After making the fields accessible (or exposing them as accessible properties instead), your options are:
Make your base class abstract, with an abstract method or property to set the value (and possibly return it) - the problem here is that you can't easily do that when the two types are different
Create an interface to do the same sort of thing, and cast to the interface
Just cast as you are now
Use dynamic if you're using C# 4 - just declare current as dynamic, and you can assign to current.value and the compiler will insert code to work it out at execution time
Redesign your code / inheritance hierarchy
Personally I would at least consider the last approach - is inheritance definitely appropriate here? Do the two types for value really need to be different? Do they have the same meaning, and if so would it make sense to push the value to the base class and potentially make it generic if you need different types?
You could instead of using a base class create an interface that has Value as a property and then have Foo and Bar implement that interface.
First, your "value" fields are not exposed as public.
Second, I don't think you won't get away from explicit casting here. Just imaging that your Bar class look like this:
public class Bar : Base
{
public string value;
}
Related
I am new to C# but seem to have noticed a limitation from what I am wanting to do with my code.
I have a class which i want to store a reference to other classes which i plan to store in a list. Something like this:
myList.Add(new Node(1,1,referenceToClassA));
myList.Add(new Node(1,2,referenceToClassB));
So my class would look like this:
public class Node : IHeapItem<Node> { //IHeapItem is for a heap i use for pathfinding
public int x;
public int y;
public ??? reference;
// constructor
public Node(int a, int b , ??? r){
x = a;
y = b;
reference = r;
}
// other unrelated stuff
}
So as you can probably guess, i have no idea what data type reference would be in my class given that it could be assigned to different classes.
I can't seem to find if there is a data type that is flexible for this in C# (i started in JavaScript so am not used to strict behavior on variable types).
What are my options here, what data type should I use, or will i have to implement this in a totally different way?
Hope you can help.
IF you only have one type of item in each list, then you could use this:
public class Node<T> : IHeapItem<Node> { //IHeapItem is for a heap i use for pathfinding
public int x;
public int y;
public T reference;
// constructor
public Node(int a, int b , T r){
x = a;
y = b;
reference = r;
}
// other unrelated stuff
}
If you don't know what you're going to get, and you will have more than one item in a list, then you're forced to use object. With a little reflection, that can work out pretty well.
It is also possible that you will have sets of different items, each set could implement the same interface, then that interface could be what you hold in the list.
If you're trying to create a generic, use T as the parameter type.
If you use T as the parameter type, you'll have to modify your class to be Node<T> as well.
Otherwise, you could use dynamic.
There is a class called Object that can reference any other class. If you want to make it just to a little group of classes, you may want to create an abstract class or an interface.
I'm currently working through the Pluralsight C# 5.0 course, and I'm relatively new to programming.
I previously thought I understood the concept of Data Types on a basic level, Int/Array/Strings etc.
In this course it starts to introduce C#'s huge emphasis on Types, and creating your own custom types.
One of the course code snippets which I've included below, is refusing to sink in and I was hoping
someone could provide some clarity or a different way of thinking about it.
Program.cs:
GradeStatistics stats = book.ComputeStatistics();
GradeStatistics.cs:
namespace Grades
{
public class GradeStatistics
{
public GradeStatistics()
{
HighestGrade = 0;
LowestGrade = float.MaxValue;
}
public float AverageGrade;
public float HighestGrade;
public float LowestGrade;
}
}
Grades:
public GradeStatistics ComputeStatistics()
{
GradeStatistics stats = new GradeStatistics();
float sum = 0f;
foreach (float grade in grades)
{
stats.HighestGrade = Math.Max(grade, stats.HighestGrade);
stats.LowestGrade = Math.Min(grade, stats.LowestGrade);
sum += grade;
}
stats.AverageGrade = sum / grades.Count;
return stats;
}
I'm finding it particularly difficult to understand what exactly GradeStatistics is.
In the course it is referred to as not only a class, but as a variable, and furthermore also
being returned as an object in Grades.
Any clarity is appreciated, as I'm finding it a little difficult to follow with all of the
above terms being thrown around.
GradeStatistics is a class, from this declaration:
public class GradeStatistics
stats is a variable of type GradeStatistics, from this declaration:
GradeStatistics stats = new GradeStatistics();
The return type of ComputeStatistics is GradeStatistics, from this declaration:
public GradeStatistics ComputeStatistics()
So, it's a class. It is being used to declare a variable with a particular type, and it is used to declare what a particular method will return, an object of the type.
If it helps, you can sort of think of a type as a blueprint. You can have a blueprint of a house. This will tell you that "if you had a house", this is what it would look like.
When you construct an instance of the type, ie. build the house, you get an instance. It has a type (it follows the blueprint), but it may be different from other instances, having other property values (like the color of the paint used, or the style of doors).
First, GradeStatistics is a Class.
Second, it is not referred as a variable anywhere. But stats is actually a variable of type GradeStatistics in this line.
GradeStatistics stats = new GradeStatistics();
Third, ComputeStatistics is a function which return GradeStatistics.
And if you have read OOP than you should know that any object of any class type can be returned as a function return value.
GradeStatics is a class by definition. When you use the new keyword you are creating an instance of that class (an object) which you can pass around or assign it to a variable.
So your snippets above, GradeStatistics is defined as a class in the gradestatics.cs file. Grades.cs creates an instance of this class in the computestatics method and assigns it to the stats variable which is populated in yhat method and then returned
GradeStatistics is a class. From this snippet:
public class GradeStatistics
{
public GradeStatistics()
{
HighestGrade = 0;
LowestGrade = float.MaxValue;
}
public float AverageGrade;
public float HighestGrade;
public float LowestGrade;
}
However, in the method ComputeStatistics, the return type is GradeStatistics, not void as you are probably accustomed to. This means that ComputeStatistics returns a GradeStatistics. Lets look at an easier example.
Suppose we have a class Foo. It is constructed like:
public class Foo
{
public int a;
public int b;
public Foo()
{
a = 0;
b = 0;
}
}
Now we can create Foos and access them normally.
Foo foo = new Foo();
foo.a = 4;
foo.b /= 2;
Now suppose we want to do this, except many times, so we create a method.
public Foo IncrementFoo(int amount, int divideBy)
{
Foo obj = new Foo();
obj.a = amount;
obj.b /= divideBy;
return obj;
}
This method creates a new object of type Foo, and returns it. You can then use this code like:
Foo newFoo = IncrementFoo(4, 2);
//foo == newFoo
I would recommend you read more here, especially about return types.
Note: In this case, it may be better to write an Extension method, especially if we want to modify a single instance of a Foo, but we don't want to get into that. Also if we were really wanting to create a new instance of Foo like that, it would be better to use a constructor.
I'm creating a list of class "Task" in a way such as this.
List<Task> toDoList = new List<Task>;
Task is a base class and have designed it as such:
public class Task : IDetail
{
string _taskName; //Task title.
string _taskDescription; //Task description.
public Task(string tn, string td) //Constructor.
{
_taskName = tn;
_taskDescription = td;
}
// Method set or return _taskName.
public string taskName
{
get
{
return _taskName;
}
set
{
_taskName = value;
}
}
//Method to set or return _taskDescription.
public string taskDescription
{
get
{
return _taskDescription;
}
set
{
_taskDescription = value;
}
}
public virtual void editList()
{
Creator editCreator = new Creator();
editCreator.Show();
}
}
What i've been trying todo is call methods that exists within the inherited class like one the one i have designate "Note" and have defined it as follows.
class Note : Task, IDetail
{
string _noteDescription;
public Note(string nd, string tn, string td) //Constructor.
: base(tn, td)
{
_noteDescription = nd;
}
//Method to set or return _noteDescription.
public string noteDescription
{
get
{
return _noteDescription;
}
set
{
_noteDescription = value;
}
}
public override void editList()
{
noteBuilder editNote = new noteBuilder();
editNote.Show();
}
}
However when i try to call a method of the inherited task on the list i get an error. I am trying to access the method as such:
toDoList.ElementAt(x).noteDescription;
My question is how do i prevent an error from occurring?
the error states
'toDoList.Task' does not contain a definition for 'noteDescription' and no extension method etc etc.
Should i perhaps be declaring the base class as Abstract? or is there something else i am missing?
Many thanks in advance
You've got a List<Task>. That could contain any kind of Task reference - e.g. a different derived type, not a Note. Either you want a List<Note> (so it can all be type-safe), or you'll need to cast the element of the list to Note:
Note note = (Note) toDoList[x];
string description = note.noteDescription;
(Given that you've got a List<T>, you don't need to use ElementAt - use the indexer.)
Filter the list and convert them to notes, like:
var noteList = toDoList.Where(x => x is Note)
.Select(x => (Note)x)
.ToList();
then write
noteList.ElementAt(x).noteDescription;
Because Your list is a list of Task objects, not Note objects.
You'll need to cast your objects to Note objects before you can call methods of the Note class.
(toDoList.ElementAt(x) as Note).noteDescription;
or
toDoList.Cast<Note>().ElementAt(x).noteDescription;
The second option requires all objects in the list be Note objects.
notDescription is a property you have for your derived class. But here you are creating a list of your base class
List<Task> toDoList = new List<Task>;
You can not get the properties of derived class in a base class. IT works the other way. You can access the properties of base class in your child class.
toDoList contains Task elements, not Note elements. Now a Note element is a type of Task element, sure, but polymorphism only works in one direction: you can treat a subclass like its superclass, but you can't treat a superclass like a subclass without casting it first.
If you think about it, you'll realize that it has to be that way. What if you had a second subclass of Task called Foo: you can put both of those types in toDoList...if you tried to access noteDescription on an object that is of type Foo, you'd be in trouble.
However, there is a way to do what you want, it just requires a cast:
var note = toDoList.ElementAt(x) as Note;
var noteDescription = note==null ? "<not a note>" : note.noteDescription;
The other way to do it, of course, would be to move noteDescription into Todo, where it would be accessible from any subclass of Todo, but that's probably not what you want since the name implies that it belongs to Note.
class Program
{
static void Main(string[] args)
{
baseClass obj = new baseClass();
obj.intF = 5;
obj.intS = 4;
child obj1 = new child();
Console.WriteLine(Convert.ToString(obj.addNo()));
Console.WriteLine(Convert.ToString(obj1.add()));
Console.ReadLine();
}
}
public class baseClass
{
public int intF = 0, intS = 0;
public int addNo()
{
int intReturn = 0;
intReturn = intF + intS;
return intReturn;
}
}
class child : baseClass
{
public int add()
{
int intReturn = 0;
intReturn = base.intF * base.intS;
return intReturn;
}
}
I want to access intF and intS in child class whatever i input.. but i always get the values of both variables 0. 0 is default value of both variables.
Can anyone tell me that how can i get the value???
thx in adv..
Yes, Zero is what you should get, since you made single instance of child class and did not assign any value to its inherited variables,
child obj1 = new child();
rather you have instantiated another instance of base class separately and assign value to its members,
baseClass obj = new baseClass();
both runtime both the base class instance and child instance are totally different objects, so you should assign the child values separately like
obj1.intF = 5;
obj1.intS = 4;
then only you shall get the desired result.
You've got two separate objects - that's the problem. The values of the base class variables in the object referred to by obj1 are 0, because they haven't been set to anything else. There's nothing to tie that object to the object referred to by obj.
If you need to access the variables of another object, you'd have to make that object available to the one trying to access the data. You could pass obj as an argument to a method, or perhaps make it a property. There are lots of different approaches here, but we don't know what the bigger picture is - what you're really trying to do. Once you understand why it's not working as you expect it to, you can start thinking about what you're really trying to do.
Just to be clear, this has nothing to do with inheritance. It has everything to do with you creating two distinct objects. You'd get the same effect if you just used a single class, but created two different instances of that class.
Is it possible to allow methods and properties of the 'this' pointer to be resolved dynamically?
Put another way, can a class have a dynamic superclass?
Clarification
I would like to be able to subclass some class and access properties and methods that aren't defined at compile-time.
class MyClass : DynamicObject
{
public void ReceiveValue(object value) {
MyProperty = value;
}
}
DynamicObject provides a way for my code to get notified that set_MyProperty has been called with the argument value above, correct? I know this is possible if you use a syntax like:
var mc = new MyClass();
...
dynamic dmc = mc;
dmc.MyProperty = value;
But I want to be able to do this from within the methods of MyClass, almost as if I had done:
dynamic dmc = this;
dmc.MyProperty = value;
Does DynamicObject have me covered?
No, you can't have a dynamic base class. Aside from anything else, the system still needs to know how much space to allocate when you create a new instance of your class.
Could you explain what you're trying to achieve? There may well be ways in which dynamic would help without needing quite this behaviour.
EDIT: Okay, having seen your edit - I don't think you can quite do what you want, but if you just use the
dynamic dmc = this;
dmc.MyProperty = value;
or
((dynamic)this).MyProperty = value;
workaround it should be fine. To put it another way: the this reference is always statically typed, but you can have an expression with the value of this but with a dynamic type.
That shouldn't be too onerous unless you're doing a lot of dynamic work - in which case I'd recommend that you use a fully dynamic language instead. If you implement the bulk of your dynamic code in IronPython/IronRuby, you can easily integrate it with your C# code anyway.
This is the basis of polymorphism. The method/property called will be the one given lowest in the heirarchy of the objects type.
How about this:
class B
{
public void M(object o)
{
dynamic i = this;
i.P = o;
}
}
class D : B
{
public object P { get; set; }
}
class Program
{
static void Main()
{
var d = new D();
d.M(1);
}
}
I realize this is a tangent, but there are languages where every class's superclass is dynamic - i.e. where class name resolution is virtual and override-able.