0

I have this C# dictionary

var dic = new Dictionary<string, Type>() {
    { "A1", typeof(Model.ABC) },
    { "A2", typeof(Model.XYZ) }
};

How do I get the class Model.XYZ? When I use dic["A2"], I can only get typeof(Model.XYZ), but I need just Model.XYZ

The reason of the above is I can use dictionary to pass the typeof during XmlSeriliazer constructor and the class name at Deserialize method. Below is the code is now hardcoded to use Model.XYZ which I needed to get is from dictionary.

var serializer = new XmlSerializer(dic["A2"]);

using (TextReader reader = new StreamReader(new FileStream(filePath, FileMode.Open)))
{
    var obj = (Model.XYZ)serializer.Deserialize(reader);
}
Steve
  • 2,963
  • 15
  • 61
  • 133
  • 8
    What do you mean by "get the class"? What are you actually trying to accomplish with this dictionary? I think you have an X/Y Problem. – Dai Mar 13 '21 at 02:09
  • Actually, I need the class name for my XmlSerializer object to run Deserialize(). – Steve Mar 13 '21 at 02:11
  • 1
    consider using nameof() function if i got this correctly – Duck Ling Mar 13 '21 at 02:13
  • @DuckLing, sorry, I don't get it. Is it `nameof(dic["A2"])`? I still need to use `typeof` – Steve Mar 13 '21 at 02:20
  • 1
    Your class names are `Model.XYZ` and `Model.ABC`? I honestly think you mean property names. – Trevor Mar 13 '21 at 02:28
  • @Codexer yes. they are the class name. – Steve Mar 13 '21 at 02:30
  • 4
    Don't you pass a [`Type` to the `XmlSerializer` constructor](https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer.-ctor?view=net-5.0#System_Xml_Serialization_XmlSerializer__ctor_System_Type_)? You have a `Type` stored in your dictionary, so just pass that. – Heretic Monkey Mar 13 '21 at 02:33
  • 2
    @Steve why not `dic["A2"].FullName`, which includes namespace + classname and or `dic["A2"].Name` for just the classname? You've stored the types, now you need just a property on that type... – Trevor Mar 13 '21 at 02:40
  • @Codexer, I tried both but it has syntax error. `var obj = (dic["A2"].FullName)serializer.Deserialize(reader);` but if `var obj = (Model.XYZ)serializer.Deserialize(reader);`, no error. But, I need to make it dynamic, not hardcoded. – Steve Mar 13 '21 at 05:01
  • @HereticMonkey, yes I can pass the type to XmlSerializer constructor dynamically from dictionary now. But when I deserialize it, I do not know how to get the type from dictionary. – Steve Mar 13 '21 at 05:04
  • 3
    Oh, you're expecting to store a Type in a dictionary, then write code that gets it out and casts to something of that type, then proceeds using whatever type was stored in the dictionary. It won't work; C# is statically typed. If you want to code like that you need something more like JavaScript – Caius Jard Mar 13 '21 at 05:58
  • @CaiusJard at the moment my solution is to use dynamic type. `var obj = (dynamic)serializer.Deserialize(reader);` But if I can define the specific type, it will be better. – Steve Mar 13 '21 at 06:03
  • 1
    You can define a specific type by writing the type name in brackets, but you can be sure the compiler won't go rummaging in a dictionary, dig out a value, patch it into your source code and proceed as if that is what you'd written.. and hopefully then when you've grok'd that you can see why it definitely wouldn't work that way at runtime (because it couldn't, because the compiler takes type specifications and bakes them in). If you want to get that level of funky you're into reflection or dynamic recompilation, or as you've found - turning C# into JavaScript by going `dynamic` – Caius Jard Mar 13 '21 at 06:08
  • 1
    (but then you can't eat your type safety cake and have it too) – Caius Jard Mar 13 '21 at 06:13
  • @CaiusJard, yeah I love the type safe :) now I am looking into Factory method. Maybe that will simplify the solution. – Steve Mar 13 '21 at 06:25
  • 2
    One of the main thrusts of OO languages is that we group objects into hierarchies based on similar attributes. If you have a bunch of XYZ type objects that you want to treat in a similar way then you make an inheritance hierarchy of them or have them all implement the same interface, then you can cast them to that interface or type and treat them equivalently. If the objects you're wanting to deser from and create have no resemblance to each other then this won't help, but neither will a factory method.. – Caius Jard Mar 13 '21 at 06:32
  • 4
    The biggest problem with this question is that you haven't said what the problem is, you e just come up with a broken solution, found that it's broken, and come saying "this is broke, how to I fix it" - in essence you've brought us a hammer with a snapped handle, asked us to fix it so you can go hit your TV with the hammer and see if that cures the black screen. It would be better for us to look at the TV so we can see if the fuse needs replacing, because if it does then hitting it with a hammer won't work anyway – Caius Jard Mar 13 '21 at 06:35
  • @CaiusJard, thanks for the pointers. Okay, I have added some code in the original post – Steve Mar 13 '21 at 06:45
  • 3
    The problem with the cast you'd want to do, `var obj = (dic["A2"])serializer.Deserialize(reader)`, is that you can't do anything meaningful with `obj` in code thereafter, because neither you nor the compiler will know what type `dic["A2"]` will be until at runtime. Explain _why_ you'd want to cast it, and to what. Perhaps all your types share some common properties, then you'd put those in an interface, apply them to those classes and then at that line in code you cast them to that interface. – CodeCaster Mar 13 '21 at 06:49
  • @CodeCaster, you are right. I am re-designing it now. thanks. – Steve Mar 13 '21 at 07:07
  • 1
    @CaiusJard Inheritance in OOP needs to die. Inheritance _can_ make sense in some cases, but 90% of the time people use inheritance as a _poor-man's mixin_, and confounding things: most of the .NET ecosystem actually encourages using inheritance not for polymorphism, but to avoid the tedium of repeating class members (e.g. in ASP.NET View Models). And the framework prefers passing class objects instead of interfaces. We're told to prefer composition where possible but C# still makes doing composition correctly hard. _\*grumble\*_ Yeah, I'm ranting. – Dai Mar 13 '21 at 08:54
  • @Dai, actually I am trying to implement design pattern. From your experience, how important is this GoF design pattern in latest .NET Core 3.1 Framework? – Steve Mar 13 '21 at 09:42
  • 1
    @Steve That question makes absolutely no sense (what pattern *specifically* are you trying to implement **and why?**). Being an SWE is all about understanding the problem space and applying appropriate solutions - but it sounds to me like you don't understand the problem space and aren't thinking about how you're solving the problem either. Someone who understands OOP and has read the GoF book would not be asking a question like that. – Dai Mar 13 '21 at 09:54
  • @dai, I think you misunderstood. Actually it's a just a general question. Nothing to do with this post. – Steve Mar 13 '21 at 10:04
  • 1
    Variables have a meaningful type _only_ at compile time. Your "cast" in your example makes no sense, because if you wait until run time to do it, there's no way for it to affect the _variable_ to which you're assigning the object. The _instance_ of the object itself is _already_ an instance of the type you want. If you want to _do_ something with the object, you have to know something about its type at compile time (e.g. base type, implemented interface), use reflection, or use a `dynamic` variable (i.e. if the common member(s) you want aren't part of a type hierarchy). See duplicate. – Peter Duniho Mar 18 '21 at 00:45
  • 1
    Now, addressing your first comment above... _"I need the class name for my XmlSerializer object to run Deserialize()"_ -- no, you should not need that. The `XmlSerializer` already has the type, passed to it in the constructor, and so the `Deserialize()` method can do its job without any more information. – Peter Duniho Mar 18 '21 at 00:48

0 Answers0