Accessing fields in a derived class - c#

I'm creating a list of nodes on the fly through a user interface. In my List I can add any number of objects (AAA, BBB, etc) to the List based on the class structure below by instantiating these objects through reflection.
public abstract class Node : IDisposable
{
protected int x;
}
public class AAA : Node
{
public int iA;
}
public class BBB : Node
{
public int iB;
}
After creating the List I want to access the the extended fields in the derived objects. I know that I have to downcast to access the extended fields but in order to do that presently I have to perform an explicit cast.
foreach (Node nn in MyList) //assume the first node in the list is AAA
{
int m = ((namespace.AAA) nn).iA; //this works
int n = (AAA) nn).iA; //this works
}
I was wondering if I can use a string to create the actual downcast. Maybe it can't be done. Maybe I'm missing something. What I would like to do which DOESN'T work would be something like the following.
foreach (Node nn in MyList) //assume the first node in the list is AAA
{
Type t2 = nn.GetType(); //{Name = AAA; FullName = namespace.AAA} (*debugger*)
string str = t2.FullName; //namespace.AAA
int m = ((str) nn).iA; //this DOESN'T work
}
When I look at the value of nn in the debugger the FullName represents the Class I want to use for the downcast.
I could get around this by using a switch statement based on the string representing the class and hard code in the cast statement but because I have over 100 different nodes and I will be adding more nodes in the future, I would have to modify the switch statement every time a node is added. This is something I would prefer not to do if all possible.
Thanks in advance for any response.
Thanks to Douglas for pointing out that I could use FieldInfo to get the value of iA for example. I just wanted to expand a little more on this topic. If I wanted to take Class AAA and extend it through composition would I also be able to access the fields in those classes through the FieldInfo.
public class AAA : Node
{
public int iA;
public X[] XArray; //where X is some other random class with pubic fields
public Y[] YArray; //where Y is some other abstract class
}

What you are doing seems like a product of a faulty idea somewhere in your design.
Instead of having iA and iB in your classes, why doesn't the base node have a property called iNodeImplementation which you set in the constructor of AAA or BBB? Then you don't have to do all this fancy casting.
I have a feeling your trying to be too cute and missed some basic OOD principles. Consider how you can refactor your classes to make your code simpler.

Without going into the merits of whether this should be done, here's some sample code showing how it can be done using reflection:
Type aaaType = Type.GetType("namespace.AAA");
FieldInfo iAField = aaaType.GetField("iA", BindingFlags.Public |
BindingFlags.Instance);
int m = (int)iAField.GetValue(nn);

Why you don't try to set abstract properties in Node class and than implement in AAA and BBB.
public abstract class Node : IDisposable
{
protected int x;
public abstract int i;
}
public class AAA : Node
{
public override int i;
}
public class BBB : Node
{
public override int i;
}
And than use the foreach like this:
foreach (Node nn in MyList)
{
int m = nn.i;
}

To me, this is a problem in your object design, not in C#.
You've got a lot of nodes that you want to treat generically (great) but you want to be able to get specialized data from them in unique ways. This is not so great in the context of having a (possibly) unbounded amount of unique data.
The problem is that you want the best of both worlds: unique encapsulated data and free generic access to that data.
I would say that you need to take your Node design and think long and hard what kind of operations/accessing should be available to generic consumers of the nodes and provide that in an abstract base class or a small(ish) number of interfaces that provide that access.
Otherwise, you're looking at a lot of down-casting somewhere in your code or work with reflection to best guess things or a standard interface for describing and getting the values you want.

Related

How to sort a List<> that contains derived class objects, by derived class method

I have a double problem here. I need to sort a List<> that I know contains objects of a derived class to the class that the list was declared to contain originally. AND, I need to sort by the return value from a method in that derived class, which takes a parameter. Keep in mind that I already know the List contains objects all of the derived class type.
I've created some sample code here to demonstrate the question since the real code cannot be shared publicly. Note, I have no control over the base conditions here (i.e. the fact that the List<> collection's declared contents are the parent class and that it contains objects of the derived class, which contains a method that takes an argument and returns the values that I need to sort the collection by). So, I doubt I'd be able to use any suggestion that requires changes there. What I think I need is a way to specify (cast?) what is really in the List so I can access the method defined there. But I'm open to other thoughts for sure. Otherwise I'm left with a traditional bubble sort. Thanks.
public class Component
{
public int X;
public int Y;
}
public class ComponentList : List<Component>
{
// Other members that deal with Components, generically
}
public class Fence : Component
{
public int Distance(int FromX, int FromY)
{
int returnValue = 0;
// Caluclate distance...
return returnValue;
}
}
public class Yard : Component
{
// Yada yada yada
}
public class MyCode
{
public List<Component> MyFences;
public MyCode(List<Component> Fences, int FromX, int FromY)
{
// Sort the fences by their distance from specified X,Y
Fences.Sort((A as Fence, B as Fence) => A.Distance(FromX, FromY).CompareTo(B.Distance(FromX, FromY)));
// Or
List<Fence> sortedFences = MyFences.OrderBy(A => A.Distance(FromX, FromY)).ToList();
// Or ???
}
}
Use the Enumerable.Cast<Fence> extension method to transform your IEnumerable<Component> to IEnumerable<Fence>. Then I'd use your second approach (the OrderBy approach) to sort it, but that's my preference.
List<Fence> sortedFences = MyFences.Cast<Fence>().OrderBy(A => A.Distance(FromX, FromY)).ToList();
This approach will throw if there is an object in MyFences that can't be cast to Fence. If you expect that the code should only be passed Fences, this might be what you want. If, instead, you want to skip over non-Fence members, you can use:
List<Fence> sortedFences = MyFences.OfType<Fence>().OrderBy(A => A.Distance(FromX, FromY)).ToList();

Data type for a variable that can be different types

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.

C# Getting access to subclass variable while operating on superclass objects

I am building a simple german learning helper program and one of its elements is a dictionary. To manage all the words, I've added three classes: Noun, Adjective and Verb. They all inherit from another abstract class Word. The noun class also contains an Article enum.
All the words (Adjective, Noun and Verb objects) are stored in a List<Word>.. I have trouble printing them in ListView columns or more specifically - getting access to the field I want.
Basically, I want to loop through all the words in the List. While doing this, check if current item is a noun (Noun type of object) - if so, get its article. If not, print "--" and then add the word translations to columns.
Here is the method:
private void UpdateList(List<Word> currentWordList) //passing the List
{
wordsListView.Items.Clear();
int index = 1; // first column of the number
foreach (Word w in currentWordList)
{
ListViewItem newItem = new ListViewItem("" + index);
if (w is Noun)
newItem.SubItems.Add(w.Article); //here is the error (no definition for "Article")
else
newItem.SubItems.Add("--");
newItem.SubItems.Add(w.GermanTranslation);
newItem.SubItems.Add(w.PolishTranslation);
wordsListView.Items.Add(newItem);
}
}
How do I solve this?
Thank you very much for your help.
You could cast w to Noun like this:
Noun noun = (Noun)w;
Then use the noun variable to access the Article.
Having said that, a better way to do it is to define an abstract method in Word called something like GetDescription that gets the description of the word.
Here is an example:
public abstract class Word
{
public abstract string GetDescription();
//....
}
public class Noun : Word
{
public override string GetDescription()
{
//Here you can access the Article property
//...
}
//...
}
Then in the loop, you can use the GetDescription method to get the description of each word.
You need to cast W to the Child Class. Like so
newItem.SubItems.Add(((Noun)w).Article)

C# type argument constraints

I'm trying to do something a certain way... but I'm certain there's a better way
public interface IMix
{
T Mix<T>(List<T> values) where T : IMix;
}
The problem with this is that if I want to "Mix" 5 values, then I need to do value1.Mix(others) but that is not clean. Plus, the type of T needs to be the same type as whatever class implements the interface. So, this doesn't really work.
I was thinking something like this:
public static class MixWrapper
{
public static T Mix<T>(List<T> values);
}
But that obviously won't work because I have to define the body in MixWrapper
EDIT: to clear up some misunderstanding, these are not real math averages, I could just as easily say "Fuse" or anything else. For example I could be trying to "average" a list some struct or other class.
EDIT 2:
One example could be a class like this
class Sequence : IMix
{
List<int> sequence;
double period;
double weight;
}
The "Mix" in this case would need to return a Sequence that was built this way: the resulting period is the weighted average of the periods based on the weight. The weight is the sum of the weights, and the sequence is the weighted average of the sequences after they have been timescaled down to the resulting period. Suffice to say, any complicated method that you could think of needs to be accounted for
If you want to calculate average of some list, then you can use LINQ:
var value = list.Average(x => x.SomeProperty);
Put the type T on your interface and just fill it with the same type as the class when you're implementing it:
public interface IMix<T>
{
T Mix(List<T> values);
}
public class ConcreteObjects : IMix<ConcreteObjects>
{
public ConcreteObjects Mix(List<ConcreteObjects> values)
{
// do mixing
}
}
This also leaves the door open for other classes to be able to mix ConcreteObjects if need be.
I think you're looking for an extension method.
You need to define a static method somewhere (some helper class, I suppose) like this:
public static T Average<T>(this List<T> list) where T : IAverage
{
return // average stuff
}
Now you just need to include your helper class with using and you can do something like this:
AverageClass implements IAverage
List<IAverage> list = new List<AverageClass>();
var average = list.Average();

Retrieving static members of multiple classes programmatically

I am not sure the best approach to this problem, be it through reflection, redesigning my classes altogether, or doing something simple.
Basically I have a base class, and I can have any number of subclasses which inherit from it. Let's call the base class Shape and the subclasses CircleShape, RectangleShape, etc.
The base class is never itself instantiated, only the subclasses. Some are never instatiated, some are instantiated many times throughout the life of the program.
Sometimes I need information specific to a subclass before I instantiate it. Right now I use an enum to differentiate all subclass types. And I instantiate each subclass based on the enum in a switch statement, like this:
switch (shapeType)
{
case CircleShape:
shape = new CircleShape();
case SquareShape:
shape = new RectangleShape();
}
But say instead of having to use this kind of hardcoded switch statement, I wanted to enumerate through all the subclasses. Is there a way to automatically retrieve a list of subclasses and access their STATIC members for info about them (before instantiating them)? Or is it easier to manually instantiate each class once and add them to an array so an I enumerate through them (but not tie those instances to any actual data).
Or should I do something completely different?
You can use attributes to define metadata on your classes and then use reflection to read this metadata at runtime to decide what you want to do with this class without having to instantiate it.
Here's some information on using attributes (you can create your own custom attributes too) using attributes in C#
Here's a quick sample of what this would look like:
Class Defenition:
// ********* assign the attributes to the class ********
[BugFixAttribute(121,"Jesse Liberty","01/03/05")]
[BugFixAttribute(107,"Jesse Liberty","01/04/05", Comment="Fixed off by one errors")]
public class MyMath
{
...
Using Reflection to read the attributes:
// get the member information and use it to retrieve the custom attributes
System.Reflection.MemberInfo inf = typeof(MyMath);
object[] attributes;
attributes = inf.GetCustomAttributes(typeof(BugFixAttribute), false);
// iterate through the attributes, retrieving the properties
foreach(Object attribute in attributes)
{
BugFixAttribute bfa = (BugFixAttribute) attribute;
Console.WriteLine("\nBugID: {0}", bfa.BugID);
Console.WriteLine("Programmer: {0}", bfa.Programmer);
Console.WriteLine("Date: {0}", bfa.Date);
Console.WriteLine("Comment: {0}", bfa.Comment);
}
NOTE: Be careful with using reflection too heavily on large numbers of iterations of large number of objects though, since it comes with a significant performance cost.
You could use reflection to enumerate all your classes, but this is not a very efficient way to do things since it is kind of slow.
If they are all in the same assembly you could do something like:
class Shape
{
/* ... */
}
class CircleShape : Shape
{
public static string Name
{
get
{
return "Circle";
}
}
}
class RectangleShape : Shape
{
public static string Name
{
get
{
return "Rectangle";
}
}
}
class Program
{
static void Main(string[] args)
{
var subclasses = Assembly.GetExecutingAssembly().GetTypes().Where(type => type.IsSubclassOf(typeof(Shape)));
foreach (var subclass in subclasses)
{
var nameProperty = subclass.GetProperty("Name", BindingFlags.Public | BindingFlags.Static);
if (nameProperty != null)
{
Console.WriteLine("Type {0} has name {1}.", subclass.Name, nameProperty.GetValue(null, null));
}
}
}
}
Of course you could also use attributes instead of static members which would probably preferable if you want to decorate the classes with information that you wanted to look up at runtime. There are many examples of how attributes work around the internet.

Categories