C# store different child classes and call them at same time - c#

Actually all these classes are defined in the 3rd lib, so I can't change them.
=====================
I'm learning C# and I met a problem.
Suppose I have a parent class and two child classes:
class ParentClass
{
....
};
class ChildA : ParentClass
{
public string name;
};
class ChildB : ParentClass
{
public string name;
};
Both class ChildA and ChildB have property name, but ParentClass doesn't.
Now I need to store ChildA and ChildB in a dictionary, so I write Dictionary<string, ParentClass>.
But I can't get name because ParentClass doesn't have this property:
foreach (ParentClass pc in dict.Values)
{
// it works, but too verbose as I may have ChildC, ChildD...
if (pc is ChildA ca)
{
ca.name
}
if (pc is ChildB cb)
{
cb.name
}
// how can I get the name property at same time?
}
how can I handle this?

The short version is "no". There are things that you could do if you have access to the types - for example, you could implement a common interface (interface IHazName { public string Name {get;} }) - but you can't do that here since you don't control the types.
A lazy way could be to abuse dynamic:
dynamic hack = pc;
hack.name = "yolo";
but... please don't! Your is approach (or perhaps a switch expression) is about as good as you can get. Note that if you need to talk to this member in a lot of places, you could move that shared logic to an extension method:
static class SomeUtilsType {
public static string GetName(this ParentClass obj) => obj switch {
ChildA ca => ca.name,
ChildB cb => cb.name,
_ => throw new ArgumentException("Unexpected object type", nameof(obj)),
};
}
...
foreach (ParentClass pc in dict.Values)
{
Console.WriteLine(pc.GetName());
}
(or a similar set method) - then at least you don't need to repeat yourself.

One way to do this is to use reflection on the type to determine if it has a "name" property (or field, as you've shown):
public static string GetName(ParentClass parent)
{
return parent.GetType().GetProperty("name")?.GetValue(parent, null).ToString()
?? parent.GetType().GetField("name")?.GetValue(parent).ToString();
}
Example usage:
static void Main(string[] args)
{
ParentClass parent = new ParentClass();
ChildA child = new ChildA { name = "ChildName" };
Console.WriteLine($"Parent name: {GetName(parent)}");
Console.WriteLine($"Child name: {GetName(child)}");
Console.Write("\n\nDone. Press any key to exit...");
Console.ReadKey();
}
Output
Parent name:
Child name: ChildName
Done. Press any key to exit...

Related

Dispatch co-variant list elements according to subclass

I have classes B and C, inheriting from class SuperA. If I have a list of SuperA containing various implementations of SuperA, how can I call method taking B and C argument according to the actual implementation of each element in the list, without having to test the type of each element (I would prefer to avoid if(item is B) stuff for open/closed principle reasons).
public class Test
{
public void TestMethod()
{
var list = new List<SuperA> {new B(), new C()};
var factory = new OutputFactory();
foreach (SuperA item in list)
{
DoSomething(factory.GenerateOutput(item)); // doesn't compile as there is no GenerateOutput(SuperA foo) signature in OutputFactory.
}
}
private static void DoSomething(OutputB b)
{
Console.WriteLine(b.ToString());
}
private static void DoSomething(OutputC c)
{
Console.WriteLine(c.ToString());
}
public class SuperA
{
}
public class B : SuperA
{
}
public class C : SuperA
{
}
public class OutputB
{
public override string ToString()
{
return "B";
}
}
public class OutputC
{
public override string ToString()
{
return "C";
}
}
public class OutputFactory
{
public OutputB GenerateOutput(B foo)
{
return new OutputB();
}
public OutputC GenerateOutput(C foo)
{
return new OutputC();
}
}
}
In the above code, I wish to print :
B
C
EDIT :
A working solution I found could be changing the item type to dynamic
foreach (dynamic item in list)
{
DoSomething(factory.GenerateOutput(item));
}
I'm open to any better idea however. As pointed out in answer, the risk of runtime error after an evolution is great.
The compiler complains about your code because, as you pointed out, threre is no GenerateOutput(SuperA) in OutputFactory class and method call resolution happens at compile type, not at runtime, and therefore is based on the type of the reference (item is a reference with type SuperA) and not on the type of the runtime instance.
You can try with different approaches:
if you find it makes sense, you can try to move polymorphic behaviour (the output text to generate) into SuperA class hierarchy, adding an abstract method or property to SuperA and implementing it differently in SuperA's subclasses
class SuperA {
public abstract string Content { get; }
}
class B : SuperA {
public string Content => "B";
}
class C : SuperA {
public string Content => "C";
}
class Test {
public void TestMethod() {
// ...
foreach (SuperA item in list) {
Console.WriteLine(item.Content);
}
}
Very simple but it does not work very well when SuperA,B, andCclasses are out of your control or when the different desired behaviours you should provide forAandBclasses does not belong toBandC` classes.
you can use an approach I like to call set of responsibility: it's something ilke the GoF's pattern chain of responsibility but without chain ;-); you can rewrite your TestMethod as follows:
public void TestMethod() {
var list = new List<SuperA> {new B(), new C()};
var compositeHandler = new CompositeHandler(new Handler[] {
new BHandler(),
new CHandler()
});
foreach (SuperA item in list) {
compositeHandler.Handle(item);
}
}
So you need define a Handler interface and its implementations like follows:
interface Handler {
bool CanHandle(SuperA item);
void Handle(SuperA item);
}
class BHandler : Handler {
bool CanHandle(SuperA item) => item is B;
void Handle(SuperA item) {
var b = (B)item; // cast here is safe due to previous check in `CanHandle()`
DoSomethingUsingB(b);
}
}
class CHandler : Handler {
bool CanHandle(SuperA item) => item is C;
void Handle(SuperA item) {
var c = (C)item; // cast here is safe due to previous check in `CanHandle()`
DoSomethingUsingC(c);
}
}
class CompositeHandler {
private readonly IEnumerable<handler> handlers;
public CompositeHandler(IEnumerable<handler> handlers) {
this.handlers = handlers;
}
public void Handle(SuperA item) {
handlers.FirstOrDefault(h => h.CanHandle(item))?.Handle(item);
}
}
This approach uses type checks (item is B), but hides them behind an interface (specifically, each implementation of the interface should provide a type check in order to select instances it can handle): if you need to add a third D extends SuperA subclass of your hierarchy root class you need only add a third DHandler : Handler implementation of Handler interface, without modify neither already provided implementations nor CompositeHelper class; the only change you should apply to existing code is the registration of the new handler's implementation in the list you provide to CompositeHelper's constructor, but this can easily be moved to you IoC container configuration or to an external configuration file.
I like this approach because it makes possibile to turn a type check based algorithm into a polymorphical one.
I wrote about this topic in a recent post on my technical blog: https://javapeanuts.blogspot.com/2018/10/set-of-responsibility.html.
You can approach the question through the GoF's visitor pattern, that is a bit more complicated than my suggested approach but was conceived precisely for such cases
You can adopt a dynamic based approach, as suggested in another response
I hope this can help you!
You can call it like this:
DoSomething((dynamic)factory.GenerateOutput((dynamic)item));
This way, using dynamic your objects will be binded at runtime to the correct methods.
With this implementation, you will have to take into consideration that you expose yourself to the risk of sending a C object for which no method was implemented and your code will still compile, but a runtime error will be generated.

Get property value defined in an abstract class

I'm working on a very simple framework, where I want to automate CRUD functions. For the purpose of this question, I've created the code below, simplified just to illustrate my issue(s).
All items derive from the (abstract) base class "DbItem" (which contains the CRUD functions), whereby the child classes provide additional functionality, and also define the table names where the DbItems are stored. For instance, "Equipment" and "Entity" both derive from DbItem, and define table names ("equipment" and "entities" respectively). However, "Entity" class is abstract and further derived by "Human" and "Animal" class. (All Humans and Animals are stored in a shared "entity" table, but equipment is stored in a separate table.)
This part of code works. The Save() method defined in DbItem properly resolves the DbTable property.
However, then I also have a DbCollection class, which extends the generic C# Collection class. I wish for the DbCollection to be able to automatically determine the correct database table name with reflection.
Hence, if I want to create a list of all equipment, I create a new DbCollection, and the code composes the appropriate SELECT statement (SELECT ... FROM equipment ...). This works.
However, if I want a list of all entities (animals and humans), I have an issue. "Entity" is marked as abstract, and I should not be able to instantiate it. However, I also do not know how to get the value of Entity.DbTable property.
A simple "fix" is to remove the "abstract" qualified from the Entity class definition. This however does not sound right to me.
Can you please let me know how can I get the value of Entity.DbTable property?
class Program
{
abstract class DbItem
{
public int Id { get; set; }
public abstract string DbTable { get; }
public void Save()
{
Console.WriteLine($"INSERT INTO {DbTable} (Id) VALUES ({this.Id})...");
}
}
abstract class Entity : DbItem
{
public sealed override string DbTable { get => "entities"; }
}
class Human : Entity { }
class Equipment : DbItem
{
public override string DbTable => "equipment";
}
class DbCollection<T> : System.Collections.ObjectModel.Collection<T>
{
public virtual string DbTable { get
{
Type t = typeof(T);
//System.Reflection.PropertyInfo p = t.GetProperty("DbName");
if(t.IsAbstract)
{
// What do we do here to get the value of Entity.DbTable?
var prop = t.GetProperty("DbTable");
// Herein lies the problem: One cannot instantiate an abstract class to provide to the GetValue() method
return prop.GetValue(null).ToString(); // System.Reflection.TargetException: 'Non-static method requires a target.'
}
else
{
var obj = Activator.CreateInstance(t);
//return (obj as DbItem).DbTable; // this also works
var prop = t.GetProperty("DbTable");
return prop.GetValue(obj).ToString();
}
}
}
public DbCollection()
{
Console.WriteLine($"SELECT Id FROM {DbTable} WHERE ...");
}
}
static void Main(string[] args)
{
var h = new Human();
h.Save(); // 1. Correctly outputs "entities";
var e = new Equipment();
e.Save(); // 2. Correctly outputs "equipment";
var ec = new DbCollection<Equipment>(); // 3. Correctly outputs "equipment"
var hc = new DbCollection<Human>(); // 4. Correctly outputs "entities"
var entityCollection = new DbCollection<Entity>(); // 5. Error.
Console.ReadLine();
}
}
Don't use a property, use an attribute. That's what you want, right? To associate a class with a table name that is fixed at compile time?
First, create a custom attribute class that stores a table name:
[AttributeUsage(AttributeTargets.Class | Inherited = true)]
public class DbTableAttribute: System.Attribute
{
private readonly string _name;
public string Name { get { return _name; } }
public DbTableAttribute(string name)
{
_name = name;
}
}
Add it to your human/animal/entity/DbItem classes:
[DbTable("entities")]
abstract class Entity : DbItem
{
//Don't need this any more
//public sealed override string DbTable { get => "entities"; }
}
And retrieve it like this:
public string GetDbTable<T>() where T : DbItem
{
var attr = typeof(T).GetCustomAttributes(
typeof(DbTableAttribute), true
).FirstOrDefault() as DbTableAttribute;
return attr?.Name;
}
What do you expect to happen in your fifth case?
There is absolutly no way to create an instance of an abstract class. remove the abstract keyword from your Entity class. If you want to prevent external creation of the Entity class you could use an internal constructor.
Since this is an collection you might also use the first entry of the collection to get the DbTable result - might be dangerous since the second item could be of another type.

How to pass an enum to a parent class's static function to instantiate a child class Part II?

This is a followup to a previous question. There was a mistake in that question (I actually posted my current solution instead of the better one I'm looking for).
I have 3 classes, ParentClass,ClassA,ClassB. Both ClassA and ClassB are subclasses of ParentClass. I wanna try to create objects of type ClassA or ClassB using some kind of enumeration to identify a type, and then instantiate the object cast as the parent type. How can I do that dynamically? Please take a look at the code below, and the part that says //what do I put here?. Thanks for reading!
public enum ClassType
{
ClassA,
ClassB
};
public abstract class ParentClass
{
public static readonly Dictionary<ClassType, Type> Types =
new Dictionary<ClassType, Type>{
{ClassType.ClassA, typeof(ClassA) },
{ClassType.ClassB, typeof(ClassB) }
};
public ParentClass()
{
//....
}
public static ParentClass GetNewObjectOfType(ClassType type)
{
//What do I put here?
}
}
public class ClassA:ParentClass
{
//....
}
public class ClassB:ParentClass
{
//.......
}
You can do it easily with the Activator class, especially if there aren't any arguments to the constructors:
return Activator.CreateInstance(Types[type]);
To restate your question: you're looking for advice on how to code a static factory method.
I don't think you need a separate enumeration to accomplish this. This is a LINQPad script I threw together (EDIT: added static constants, demo creation using them)
void Main()
{
var a = ParentClass.Create(typeof(ClassA));
var b = ParentClass.Create(typeof(ClassB));
var c = ParentClass.Create(ParentClass.ClassAType);
a.Dump();
b.Dump();
c.Dump();
}
public abstract class ParentClass
{
public static readonly Type ClassAType = typeof(ClassA);
public static readonly Type ClassBType = typeof(ClassB);
public string SomeProp { get; set; }
protected ParentClass() {}
public static ParentClass Create(Type typeToCreate)
{
// validate that type is derived from ParentClass
return (ParentClass)Activator.CreateInstance(typeToCreate);
}
}
public class ClassA:ParentClass {
public ClassA()
{
SomeProp = "ClassA~";
}
}
public class ClassB:ParentClass
{
public ClassB()
{
SomeProp = "ClassB~";
}
}
As stated in the previous question:
Reflection is slow and is often used where it isn't needed
Activator.CreateInstance uses reflection to track down a parameter-less constructor. To solve this problem - that isn't needed. The parent class already knows all of the types it is responsible for creating.
One of the reasons to use a static factory method, is that there may be substantial work, or different kinds of work involved in creating the child classes. I think if you beef up your map some, you'll have a easier time coding that static factory:
public static readonly Dictionary<ClassType, Func<ParentClass>> Types =
new Dictionary<ClassType, Func<ParentClass>>{
{ClassType.ClassA, () => new ClassA(1, 2, 3) },
{ClassType.ClassB, () => new ClassB("1") }
};
public static ParentClass GetNewObjectOfType(ClassType type)
{
Func<ParentClass> maker = Types[type];
ParentClass result = maker();
return result;
}

Dynamically add a Property to a System.object?

I got a list of different objects that I defined in different classes and I'd like to add a string property "Name" to all these objects. Is that possible ?
I don't have that much code to provide as my classes are very simple/classic ones.
Thanks in advance for any help !
(edit : I don't want to inherit from an abstract class that adds this property ! In fact, I don't want to modify at all my class that define my object. That's what i call "Dynamically" in the title.
What I want is something like :
myObject.AddProperty(string, "Name");
or
myObject.AddAttribute(string, "Name");
(I don't know how it is exactly called)
and then I can do :
myObject.Name = "blaaa";
Create an abstract class that all of your other classes could inherit:
public abstract class MyBaseClass
{
public string MyCommonString { get; set; }
}
public class Foo : MyBaseClass
{
public MyBaseClass() { }
}
//Create instance of foo
Foo myFoo = new Foo();
//MyCommonString is accessible since you inherited from base
string commonString = myFoo.MyCommonString;
EDIT (per new requirement)
Since you don't want to touch the original classes in the DLL, I'd take this [similar] approach:
public abstract class MyBaseClass
{
public string MyCommonString { get; set; }
}
//This class definition lives in the DLL and remains untouched
public class Foo
{
public Foo() { }
}
//This partial class definition lives in [insert new project name here]
public partial class Foo : MyBaseClass
{
public Foo () { }
}
Notice that Foo is now a partial class. You're not touching the existing class definition in the DLL, you're extending it.
EDIT (per newer new requirement)
Given your requirements (no editing of original class), what you're asking is not possible.
What you can do is to hard code a Hashtable named CustomProperties
Now you can fill this Hashtable with custom properties
Something like that:
MyClass myClass = new MyClass();
myClass.SetProperty("abc", 123);
myClass.SetProperty("bcd", "bla");
myClass.SetProperty("cde", DateTime.Now);
MessageBox.Show(myClass.GetProperty("abc").ToString());
class MyClass
{
private Hashtable MyProperties { get; set; }
public MyClass()
{
MyProperties = new Hashtable();
}
public object GetProperty(string name)
{
return MyProperties.Contains(name) ? MyProperties[name] : null;
}
public void SetProperty(string name, object value)
{
if (MyProperties.Contains(name))
MyProperties[name] = value;
else
MyProperties.Add(name, value);
}
}
You want to use the new C# 4.0 dynamic keyword:
dynamic obj = new System.Dynamic.ExpandoObject();
obj.Value = 10;
var action = new Action<string>((l) => Console.WriteLine(l));
obj.WriteNow = action;
obj.WriteNow(obj.Value.ToString());
You can not do this with object, but the ExpandoObject will do just fine.
But... overuse dynamic typing and you'll find yourself in a maintenance nightmare in the near future.

What OOP pattern to use when only adding new methods, not data?

In my app, I have deal with several different "parameters", which derive from IParameter interface, and also ParamBase abstract base class. I currently have two different parameter types, call them FooParameter and BarParameter, which both derive from ParamBase. Obviously, I can treat them both as IParameters when I need to deal with them generically, or detect their specific type when I need to handle their specific functionality.
My question lies in specific FooParameters. I currently have a few specific ones with their own classes which derive from FooParameter, we'll call them FP12, FP13, FP14, etc. These all have certain characteristics, which make me treat them differently in the UI. (Most have names associated with the individual bits, or ranges of bits). Note that these specific, derived FP's have no additional data associated with them, only properties (which refer to the same data in different ways) or methods.
Now, I'd like to keep all of these parameters in a Dictionary<String, IParameter> for easy generic access. The problem is, if I want to refer to a specific one with the special GUI functions, I can't write:
FP12 fp12 = (FP12)paramList["FP12"] because you can't downcast to a derived type (rightfully so). But in my case, I didn't add any data, so the cast would theoretically work.
What type of programming model should I be using instead? Thanks!
There's nothing really wrong with this approach, except for maybe storing the parameters in a dictionary. What is the purpose of doing that? Especially if you key them on their class name.
I would just use a List<IParameter> and have a control go through the collection and pick the right subclass out of there.
m_Parameters = new List<IParameter>();
//This control needs FP12
foreach(var param in Parameters) {
var fp12 = param as FP12;
if (fp12 != null) {
//do something with the param.
break;
}
}
After writing the above I think I finally understand what you are trying to do. If you want to perform an operation that is available on FP12 on any subclass of FooParameter then you need to take that operation out of FooParameter altogether. Since your parameter is data and that data is the same across different subclasses of FooParameter, it makes sense to only have one implementation of FooParameter ("data" class) and multiple "operation" classes.
//The one implementation of IParameter for all FooParameters
public class FooParameter : IParameter {
string Data1 {get;set;}
}
//base class for Foo Operation, only stores FooParameter
public class FooOperationBase {
protected readonly FooParameter m_Param;
public FooOperationBase (FooParameter param) {
m_Param = param;
}
}
//specific operations on FooParameter go in this class
public class FooOperation12 : FooOperationBase {
public FooOperation12(FooParameter param) : base(param) {}
public void DoSomeOperation() {
return m_Param.Data1 + " transformed";
}
}
If paramList["FP12"] is a FP12, that cast will work. Of course, if it's not it will throw a InvalidCastException. You could also use as, if you're not sure what type the object will be.
Whether this is an ideal design is a separate issue. Ideally, you want to prefer polymorphism, meaning the subclass of FooParameter knows to use its new special functions internally, and the outside code doesn't have to cast, or use as or is.
I'm not 100% sure where you're coming from with this question, but you could do something like this:
class Program
{
static void Main(string[] args)
{
var paramList = new List<IParameter>();
paramList.Add(new FooParameter());
paramList.Add(new BarParameter());
paramList.Add(new F1());
paramList.Add(new F2());
foreach (var p in paramList)
{
p.DoCommonOperation();
DoSpecificOperation(p);
}
Console.ReadKey();
}
private static void DoSpecificOperation(IParameter p)
{
if (p is F1)
{
(p as F1).F1Method();
}
else if (p is F2)
{
(p as F2).F2Method();
}
}
interface IParameter
{
void DoCommonOperation();
}
abstract class ParamBase : IParameter
{
public virtual void DoCommonOperation()
{
Console.WriteLine("ParamBase");
}
}
class FooParameter : ParamBase
{
public override void DoCommonOperation()
{
Console.WriteLine("FooParameter");
}
}
class BarParameter : ParamBase
{
public override void DoCommonOperation()
{
Console.WriteLine("BarParameter");
}
}
class F1 : FooParameter
{
public override void DoCommonOperation()
{
Console.WriteLine("F1");
}
public void F1Method()
{
Console.WriteLine("F1.F1Method");
}
}
class F2 : FooParameter
{
public override void DoCommonOperation()
{
Console.WriteLine("F2");
}
public void F2Method()
{
Console.WriteLine("F2.F2Method");
}
}
}
Essentially you have a method in the class that controls the list of IParameter objects that knows how to call the specific implementations, and uses is/as to do so.
Just for sanity's sake, why not use Dictionary<Type, IParameter>? With a little generics, you could do this:
public interface IParameter { }
public class FP12 : IParameter { public string fieldFP12 { get; set; } }
public class FP11 : IParameter { public string fieldFP11 { get; set; } }
public static class DictionaryHelper
{
public static T GetParameter<T>(this Dictionary<System.Type,
IParameter> target) where T : IParameter
{
return (T)target[typeof(T)];
}
}
Sample program and output:
class Program
{
static void Main()
{
Dictionary<Type, IParameter> parameters =
new Dictionary<Type, IParameter>();
parameters.Add(typeof(FP12), new FP12 { fieldFP12 = "This is FP12" });
parameters.Add(typeof(FP11), new FP11 { fieldFP11 = "This is FP11"});
// THIS IS WHERE YOU GET THE IPARAMETER YOU WANT - THE GENERICS WAY...
var fp12 = parameters.GetParameter<FP12>();
var fp11 = parameters.GetParameter<FP11>();
Console.WriteLine(fp12.fieldFP12);
Console.WriteLine(fp11.fieldFP11);
Console.ReadLine();
}
}
The resulting output:
This is FP12
This is FP11

Categories

Resources