This question already has answers here:
C#, access child properties from parent reference?
(5 answers)
Closed 4 years ago.
I am a bit confused about adding classes to a collection. In this case a Dictionary.
I got liked to a "similar" thread.. but it appears to be a totally diff rent issue. My question is about putting multiple classes in a dictionary that are inherited form a common base class. The linked thread is about storing different types like int, string, double.. etc.
class ClassName
{
public string name { get; }
public ClassName()
{
name = "name";
}
}
class Unique : ClassName
{
public string uName { get; }
public Unique()
{
uName = "UniqueName?";
}
}
class YAunique : ClassName
{
public string yaName { get; }
public YAunique()
{
yaName = "YetAnotherName";
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, ClassName> doesThisWork = new Dictionary<string, ClassName>();
doesThisWork.Add("test", new Unique());
doesThisWork.Add("test2", new YAunique());
Console.WriteLine(doesThisWork["test"].name);
Console.WriteLine(doesThisWork["test"].uName); //dose not work
Console.WriteLine(doesThisWork["test2"].name);
Console.WriteLine(doesThisWork["test2"].yaName); //does not work
Unique example = new Unique();
Console.WriteLine(example.name);
Console.WriteLine(example.uName);
YAunique example2 = new YAunique();
Console.WriteLine(example2.name);
Console.WriteLine(example2.yaName);
// Pauses the console window
Pause4Input();
}
Basically in the example above I have 3 classes, 2 of which are inherited off the same class. If I initialise either of the inherited classes I can access both the base class's variable and the child class variable (the prints at the bottom of the code)....
....but what I am trying to do is place those child classes in a dictionary.
The thing is even though it "looks" kinda right... I can only access the variables in the base class using the dictionary keys.
TL;DR I am trying to work out how to have different classes added to a dictionary collection and have all the child class functions and variables and the base class functions and variables accessible.
Thanks!
Well, it looks like you got the basics of "Inheritance" but you seem to be having some trouble about what is going to be accessible to base class and what is to derived class. So you have a Dictionary<string, BaseClass>. When you access the value in this dictionary it will be type of BaseClass. Of course it may be of the any type which derives from BaseClass as well. However, unless you cast your value to the correct type you cannot access the derived types properties, methods, etc. You should be careful on how you cast though. Please consider Pattern Matching (Starting from c#7.0)
// value is BaseClass, only methods, properties of BaseClass usable .
var value = dict["myKey"];
// Now derived classes properties etc can be accessed.
var casted = (Derived)value;
You may try leveraging polymorphism.Instead of having different "Names" properties in each derived classes, define a common property (or common properties) in base class and override them in derived classes.
using System;
using System.Collections.Generic;
abstract class ClassName {
public abstract string Name {get;}
}
class Unique : ClassName
{
public override string Name {
get{return "UniqueName?";}
}
public Unique()
{
}
}
class YAunique : ClassName
{
public override string Name {
get{return "YetAnotherName";}
}
public YAunique()
{
}
}
public class Program
{
public static void Main()
{
Dictionary<string, ClassName> doesThisWork = new Dictionary<string, ClassName>();
doesThisWork.Add("test", new Unique());
doesThisWork.Add("test2", new YAunique());
Console.WriteLine(doesThisWork["test"].Name);
Console.WriteLine(doesThisWork["test2"].Name);
}
}
Related
Below I have a class that has a property that's type is of another class:
ParentClass parentClass = new ParentClass();
public class ParentClass
{
public NestedClass nestedClassProperty { get; set; }
}
Below is the class that is used as a property in ParentClass:
public class NestedClass
{
public string someProperty { get; set; }
}
How would I pass nestedClassProperty to a method that only accepts properties that are apart of ParentClass? See the below example:
public void method1()
{
method2(parentClass.nestedClassProperty);
}
public void method2(/* Parameter should accept the nestedClassProperty
within ParentClass Note: This method should also
accept any other property within ParentClass
that's type is of another class. */)
{
/* Do something with nestedClassProperty.
Note: Every class that's nested as a property
within ParentClass will have identical properties. */
}
Thanks in advance!
Just like any other method signature, the parameter would be of the expected type:
public void method2(ParentClass.NestedClass nestedClassObject)
{
// ...
}
For classes nested within another class, the type qualifier is simply OuterClass.InnerClass.
Edit: If there can be multiple nested classes then you'd need to group them in some way, either as the parameter type or as a type constraint on a generic method. The nature of being a nested class itself isn't structurally significant to the type system.
Note what you state here:
Note: Every nested class will have identical properties.
This looks like a job for an interface:
public interface INestedClass
{
// declare the identical members
}
Then the nested classes would implement that interface:
public class ParentClass
{
// etc.
public class NestedClass : INestedClass
{
// implement the interface
}
}
The method argument would then be of the interface:
public void method2(INestedClass nestedClassObject)
{
// ...
}
The interface itself can also probably be nested like any other class.
Essentially what you're looking for is textbook polymorphism. Whether or not any given type is nested within another type makes no difference.
Yesterday, I was explaining C#'s generic constraints to my friends. When demonstrating the where T : CLASSNAME constraint, I whipped up something like this:
public class UnusableClass<T> where T : UnusableClass<T>
{
public static int method(T input){
return 0;
}
}
And was really surprised to see it compile. After a bit of thinking, however, I figured it was perfectly legal from the point of view of the compiler - UnusableClass<T> is as much of a class as any other that can be used in this constraint.
However, that leaves a couple of questions: how can this class ever be used? Is it possible to
Instantiate it?
Inherit from it?
Call its static method int method?
And, if yes, how?
If any of these is possible, what would the type of T be?
This approach is widely used in Trees and other Graph-like structures. Here you say to compiler, that T has API of UnusableClass. That said, you can implement TreeNode as follows:
public class TreeNode<T>
where T:TreeNode<T>
{
public T This { get { return this as T;} }
public T Parent { get; set; }
public List<T> Childrens { get; set; }
public virtual void AddChild(T child)
{
Childrens.Add(child);
child.Parent = This;
}
public virtual void SetParent(T parent)
{
parent.Childrens.Add(This);
Parent = parent;
}
}
And then use it like this:
public class BinaryTree:TreeNode<BinaryTree>
{
}
Well.
public class Implementation : UnusableClass<Implementation>
{
}
is perfectly valid, and as such makes
var unusable = new UnusableClass<Implementation>();
and
UnusableClass<Implementation>.method(new Implementation());
valid.
So, yes, it can be instantiated by supplying an inheriting type as the type parameter, and similarly with the call to the static method. It's for instance useful for tree-like structures where you want to generically specify the type of children the node has, while it being the same type itself.
If any of these is possible, what would the type of T be?
They are all possible, and you are the one who is gonna determine what is the type of T.For example let's assume there is a type that inherits from UnusableClass<T>
class Foo : UnusableClass<Foo> { }
Now you can instantiate UnusableClass<Foo> because Foo satisfies the constraint:
UnusableClass<Foo> f = new UnusableClass<Foo>();
Then the type of T become Foo and if you try to call method you need to pass an instance of Foo.
I was reading about extension methods and how they can extend classes with new methods without having to change the class code definition.
I wanted to know if there was any similar way by which I can add a new data member (like a List or an array) to an existing class and use the data member to store information related to the class?
Yes you can extend that class using inheritence.
public class MyClass
{
...
}
public ExtendedClass: MyClass
{
public int ExtraField {get; set;}
}
This way you have all of the members and methods (except private) that exist on the base.
With extension methods you can only extend the functionality of a class.
What you are looking for can be solved with:
Aggregation OR
Inheritance
This post may help you on deciding which one to use in your case: Inheritance vs. Aggregation
There is no way of directly adding members to a specific class.
If the class isn't sealed, you may extend that class by using inheritance. If it is sealed, you may compose yourself a new class which encapsulates the specific class you wanted to extend and extend the implementation.
For example, if you have MyClass which isn't sealed and you want to extend it, simply inherit:
public class MyExtendedClass : MyClass
{
// Add extra logic
}
or, as for composing a new class yourself, you may do the following:
public class MyExtendedClass
{
private MyClass _class;
public string MyExtraString { get; set; }
}
You can use inheritance or composition for that.
Inheritance Example:
public class Student
{
int age;// all props
}
public class MAStudent : Student // MSStudent is a student with extra stuff.
{
float maAverage;
}
Composition Example:
public class Student
{
int age;// all props
}
public class MAStudent
{
Student student;
float maAverage;
// use student's functions inside the class
}
Inheritance is the easiest way to do things. The problem with it is that it makes your classes coupled.
The good perk with inheritance that you can access every protected+ property \ method.
Although the other answers seem to be correct, the answer to your question IMHO, is that it is not possible to extend an existing class with new properties in the way that extension methods do that. Once a class is defined, you cannot 'add' things to it.
Extension method is an exception, since that is just syntactic sugar for a static helper class.
Also you can write something based on extension methods like this
public class ExistingClass
{
}
public static class ExtendingExistingClass
{
private static Dictionary<ExistingClass,List> _values = new Dictionary<ExistingClass,List>();
public List GetMyNewField(this ExistingClass t)
{
List res = null;
_values.TryGetValue(t, out res);
return res;
}
public void SetMyNewField(this ExistingClass t, List value)
{
_values[t] = value;
}
}
While developing a class library for communicating with an external database over JSON, an interesting problem arose where an upcast of an object instance resulted in one of its previously non-null members appear as null.
Many a hairs have been torn out while trying to figure out the cause of this oddity but so far I have been unsuccessful in finding a sane explanation.
Here is an example of the issue:
using System;
namespace Test
{
public class Program
{
static void Main(string[] args)
{
Descendant d = new Descendant();
d.Attributes.ToString(); // Everything fine here
Ancestor a = (Ancestor)d;
a.Attributes.ToString(); // NullPointerException
}
}
class Ancestor
{
public interface IAttributes { }
public IAttributes Attributes;
}
class Descendant : Ancestor
{
public new DescendantAttributes Attributes;
public Descendant()
{
this.Attributes = new DescendantAttributes();
}
public class DescendantAttributes : IAttributes
{
public string Name = "";
}
}
}
Error message: System.NullReferenceException was unhandled at Test.Program.Main(String[] args) in D:\Code\c#\Test\Program.cs:line 12
.NET version: 4.0
Environment: 64-bit Windows 2008 R2, Visual Studio 2010
Why does it happen? I mean, unless its a bug there probably is a design rationale behind it. What kind of situations would warrant CLR to consider a previously non-null member of an instance as null after an upcast?
When you use new modifier you are hiding the inherited property.
public new DescendantAttributes Attributes;
Look at the below link http://msdn.microsoft.com/en-us/library/vstudio/435f1dw2.aspx
When used as a modifier, the new keyword explicitly hides a member that's inherited from a
base class. When you hide an inherited member, the derived version of the member replaces the
base-class version. You can hide members without using the new modifier, but the result is a
warning. If you use new to explicitly hide a member, the modifier suppresses this warning and
documents the fact that the derived version is intended as a replacement.
In C#, the new keyword can be used as an operator , as a modifier or a constraint. MSDN Link
new operator : Used to create objects on the heap and invoke constructors.
new modifier : Used to hide an inherited member from a base class member.
new constraint : Used to restrict types that might be used as arguments for a type parameter in a generic declaration.
You are using new as a modifier here.
The new modifier is used to explicitly hide a member inherited from a base class.In your code, you are shadowing Attributes which provides a different implementation at that level of the hierarchy. So as told by Dirk, you are creating a new and unrelated property
class Ancestor
{
public interface IAttributes { }
public IAttributes Attributes;
}
class Descendant : Ancestor
{
public new DescendantAttributes Attributes; //Shadowing using new modifier
public Descendant()
{
this.Attributes = new DescendantAttributes();
}
public class DescendantAttributes : IAttributes
{
public string Name = "";
}
}
Instead of shadowing, you need overriding -
class Ancestor
{
public interface IAttributes { }
public virtual IAttributes Attributes { get; set; } // Make this virtual
}
class Descendant : Ancestor
{
// Override here OR instead you can omit the declaration at all.
public override IAttributes Attributes { get; set; }
public Descendant()
{
this.Attributes = new DescendantAttributes();
}
public class DescendantAttributes : IAttributes
{
public string Name = "";
}
}
From this post -
Suppose you have a base class and you use the base class in all your
code instead of the inherited classes, and you use shadow, it will
return the values the base class returns instead of following the
ineritance tree of the real type of the object.
I have an object like this
public class Simple
{
public string Value
{
get { return GetProperty(); }
}
// different methods, fields, events, etc.
}
Possible to replace instance of the class Simple with equal object, but with setter?
How to implement ...
private object Substitution(object simple)
{
object newSimple;
// implementations
newSimple.Value = "data";
return newSimple;
}
To have something like this
public class Simple
{
public string Value { get; set; }
// my methods, fields, events ...
}
I thought to create a class and inherit from SystemObject, then you can create different dynamic properties, but could not do :(
Or maybe try to inherit from this object (how?) and override the properties?
Thanks
You can't change the definition or structure of a loaded type at runtime.
You could, potentially, make a new type that had a similar set of properties and fields, with the property setter added. However, this is going to be of limited use in most cases, as the existing code will not understand the new type (since it's runtime generated), so would still be working off the existing type, which won't be compatible.
Typically, if you need runtime extensibility within a type, there are other options, including using a Dictionary<T,U>, or dynamic with ExpandoObject, or some other mechanism for storing "extra" information within a class that is not known at compile time.
You couuld always use an interface, that only defines a property getter. Then in the implementation have a property setter?
class Program
{
static void Main(string[] args)
{
IMyClass myA = new ClassA{ Property = "Class A" };
Console.WriteLine(myA.Property);
// can't do this
// myA.Property = "New Property";
// can do this
(myA as ClassA).Property = "New Property";
Console.WriteLine(myA.Property);
}
}
interface IMyClass
{
string Property { get; }
}
class ClassA : IMyClass
{
public string Property { get; set; }
}
Failing that, you could do an user defined conversion using the explicit keyword, more info at MSDN