I have a problem while working with GetFields() method while trying to get all the fields from a user defined class.
I have a parent class with, lets say two public fields, and another class that inherits from the parent and overrides one of the parent fields with the new keyword.
Problem comes when I use the GetFields method with the second class, because it's returning all the fields, including the overriden one. Is there something that I am doing wrong or a solution for only getting in this case the GoodBye field from the Parent class and the only one Hello field, the one from the inherited class?
This is a simple example of what I'm saying:
public class Foo
{
public string Hello = "sdfsafda";
public string GoodBye = string.Empty;
}
public class Bar : Foo
{
public new string Hello = "jl";
}
static void Main(string[] args)
{
var a = new Bar();
var derp = new List<string>();
foreach (var fieldInfo in a.GetType().GetFields())
{
derp.Add(fieldInfo.Name);
}
Console.WriteLine(derp.Count);
// writes 3 instead of 2
}
About using Properties instead of Fields, I'm afraid I can't use them right now because of limitations that are not in my hand to solve in the project I'm working on.
It seems there is no pre-collected information about shadowed fields available. If you just need a simple workaround, you can first get the names of all fields without duplicates and then use GetField(fieldName) to only get the most derived field instance:
var type = a.GetType();
foreach (var field1 in type.GetFields().Select(x => x.Name).Distinct())
{
var fieldInfo = type.GetField(field1);
derp.Add(fieldInfo.Name);
Console.WriteLine(fieldInfo.DeclaringType);
Console.WriteLine(fieldInfo);
}
ofcourse, if you only need the field names like in your question code, instead of the FieldInfo object, you can stop after the .Select(x => x.Name).Distinct().
Related
I'm using C# with the .NET 6 framework. I have a class called
Message and another called TaggedMessage which inherits from Message.
The idea is simple. A function receives an object of type Message and then adds several Tags to it and returns it as a TaggedMessage. A list of TaggedMessage objects is later displayed in a table. For databinding to remain nice and easy I want TaggedMessage to not contain nested properties. So it shouldn't hold an instance of Message for example. Instead it should contain all the properties from Message plus additional ones.
So I thought it should inherit from Message. However I cannot find a way to instantiate TaggedMessage from Message unless I specifically assign every column from Message to TaggedMessage in its constructor. Which seems overly difficult and would mean everytime I add a property to Message, I would have to revisit the constructor of TaggedMessage. Exmaple (obviously the real thing is more complex)
public class Message
{
public string MessageID { get; set; } = "5";
public string Subject{ get; set; } = "Test";
}
Public class TaggedMessage : Message
{
public string MyTag { get; set; }
}
Message m = new Message();
TaggedMessage t = TaggedMessage;
t = (TaggedMessage)m; //This ovbiously doesn't work
t.Tag = "Nature";
Now the casting doesn't work because I'm casting a base class in a derived class. But then, how to I get the values from m into t? Let's assume m has 50 properties and they could change in the future. How can get an object t that has all the values m had, but with extra tags added? There must be a more elegant way than assigning all 50 properties in the constructor!? I feel like I'm missing a simple solution here.
Message object cannot be cast to a TaggedMessage type.
What are you looking for is called mapping and there are a lot of libraries for that, including but not limited to Automapper, Mapster or ExpressMapper for example.
AutoMapper:
static void Main()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Message, TaggedMessage>()
.IncludeAllDerived();
});
var mapper = config.CreateMapper();
var m = new Message() { MessageID = "SomeMessageID", Subject = "SomeSubject" };
var t = mapper.Map<TaggedMessage>(m);
t.MyTag = "MyTag";
Console.WriteLine(t.MessageID);
Console.WriteLine(t.Subject);
Console.WriteLine(t.MyTag);
}
There are certain ways to do what you intend to do without bothering writing the mappings manually.
One of them is using a library that does it for you, like AutoMapper as Viachaslau suggests.
Another can can be serializing and deserializing the object:
var message = new Message();
var str = System.Text.Json.JsonSerializer.Serialize(message);
var taggedMessage = System.Text.Json.JsonSerializer.Deserialize<TaggedMessage>(str);
taggedMessage.MyTag = "Nature";
Both alternatives to writing that code in the constructor have their cons and can be expensive in their own ways depending on the use case, so it's not about whether you can avoid it, but about whether you should do it or not!
public class E
{
public static List<Tranzactie> tranzactie = new List<Tranzactie>();
}
public class Tranzactie
{
public string name;
public string contract;
}
static void main()
{
where i have a method with a loop that parses a.txt file
and passes extracted values to Tranzactie
}
In class E there is a list i want to populate with values extracted from parsing a txtfile in Main. The data collected in Main fills fields from class Tranzactie.
How do i put the values passed to "Tranzactie" into the list found in class E?
Well, somewhere in your loop, you'll need to:
instantiate a new Tranzactie object
populate the name and contract fields
add this object to your List<Tranzactie>
So, here's the code to do just that part:
// assuming you have variables "name" and "contract" that hold necessary data
var tranzactie = new Tranzactie()
{
name = name,
contract = contract
};
E.tranzactie.Add(tranzactie);
As an aside, I would rename the List<Tranzactie> in class E to tranzactii, because it represents multiple transactions - a collection - so plural form of the word is typically preferred.
Thank you for all your messages that really helped me, I finally decide to post here. I just discovered Tuples which allow me to create List of List with other element.
Here is my simplified code :
public class Category { //Classe "Category" comprenant le nom de la category et sa proportion de CIR
public string category_name {get; set;}
public string proportion {get; set;}
}
public static void Main(string[] args)
{
var Projects = new List<Tuple<string, List<Category>>>();
while(...)
{ [...]
var List_Categories = new List<Category>()
while(...)
{ [...]
List_Categories.Add(category_example);
}
Projects.Add(Tuple.Create(nom_projet, List_Categories);
}
}
My "Category" class is just 2 strings. A "project" is a List AND a string (project_name) hence my using of Tuple for this.
1st question : I would have create a class for "project" but I could not find how to put a Tuple as a parameter of a class ? (he do not recognize the "var" type as a parameter)
Then, 2nd question : I have an issue : when the program going on, inside "Projects" (which is a List of "project"), the "project_name" is writting well but the "Category" data is each time replaced by the new one for EVERY index of the list. I do not know how such a thing is possible ...
Thank you very much, I hope you can understand my problem, I am very sorry about my English but it is not my native language. I will reformulate if it's not understandable.
It doesn't seem like you want a tuple as a property in your project class, it seems like what you want is this:
public class Project
{
public string project_name {get; set;}
public List<Category> categories {get; set;}
}
And as Corak mentioned, I think a Dictionary might help with your other issue.
By the way, the reason you can't use var as the type of a property is that it isn't a type -- it's just a shorthand way of declaring a variable without explicitly specifying the type of that variable (the compiler figures it out), but it only works on local variables. You can't use it for a property because the compiler would have no way to figure out what the type of that property is supposed to be. The type of a tuple is Tuple<T1, T2,...> -- for example, your tuples here are Tuple<string, List<Category>>, and you could certainly have a class property of that type if you wanted.
Try using a dictionary instead
public static void Main(string[] args)
{
var Projects = new Dictionary<string, List<Category>>();
while(...)
{ [...]
var List_Categories = new List<Category>()
while(...)
{ [...]
List_Categories.Add(category_example);
}
Projects.Add(nom_projet, List_Categories);
}
}
By creating a tuple on every single loop, you are overwriting previous work. With a dictionary you can simply add to your collection inside of your loops
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.
In C#, I am defining a static field of a specific class. From within the class, I want to be able to display the name of the static field, pretty much like this:
public class Unit {
public string NameOfField { get { return ...; } }
}
public static Unit Hectare = new Unit();
If I now access:
Hectare.NameOfField
I want it to return:
Hectare
I know there is a static function System.Reflection.MethodBase.GetCurrentMethod(), but as far as I can tell there is no way to get the name of the instance containing this current method?
There is also the System.RuntimeFieldHandle structure, but I have not been able to identify any GetCurrentFieldHandle() method.
I am not sure if I am missing something obvious?
Any help on this is very much appreciated.
You should not count on variable names in you developments as they do not exits at runtime.
It's better to initialize Unit with a name directly:
public class Unit {
public Unit(string name)
{
NameOfField = name;
}
public string NameOfField { get; private set;} }
}
public static Unit Hectare = new Unit("Hectare");
Only way around this will be to store that information in the class:
public static Unit Hectare = new Unit("Hectare");
When your code is compiled all variable names are lost and replaced by internal references. There is no way to get that name again.
You can use Reflection to obtain class Fields and properties. Like below:
Suppose you have class with one property:
class Test
{
public static string MySupperField
{
get
{
return "Some symbols here";
}
}
}
......
You can read the property name in such way:
public string[] GetClassStaticNames(Type T)
{
string[] names;
System.Reflection.PropertyInfo[] props = T.GetProperties(); // This will return only properties not fields! For fields obtaining use T.GetFields();
names = new string[props.Count()];
for (int i = 0; i < props.Count(); i++)
{
names[i] = props[i].Name;
}
return names;
}
Hope this will help.
[EDIT]
Returning to your question - No you cant obtain name of current variable.
What you are asking about cant be done because of classes nature, they are objects in memory and reference to one object can be held in many variables, and when you are requesting value of instance field or property it will be actually performed operation with object in memory not with variable wich holds reference to that object. So obtaining name of variable wich holds reference to current instance have no sence
Thanks everyone who has taken the time to answer and discuss my question.
Just to let you know, I have implemented a solution that is sufficient for my needs. The solution is not general, and it has some pitfalls, but I'd thought I share it anyway in case it can be of help to someone else.
This is in principle what the class that is used when defining fields looks like:
public class Unit : IUnit {
public NameOfField { get; set; }
...
}
As you can see, the class implements the IUnit interface, and I have provided a public setter in the NameOfField property.
The static fields are typically defined like this within some containing class:
public static Unit Hectare = new Unit();
My solution is to set the NameOfField property through reflection before the field is used in the implementation.
I do this through a static constructor (that of course needs to be invoked before the Unit fields are accessed.
I use Linq to traverse the executing assembly for the relevant fields, and when I have detected these fields (fields which type implements the IUnit interface), I set the NameOfField property for each of them using the Any extension method:
Assembly.GetExecutingAssembly().GetTypes().
SelectMany(type => type.GetFields(BindingFlags.Public | BindingFlags.Static)).
Where(fieldInfo => fieldInfo.FieldType.GetInterfaces().Contains(typeof(IUnit))).
Any(fieldInfo =>
{
((IUnit)fieldInfo.GetValue(null)).NameOfField= fieldInfo.Name;
return false;
});
There are some shortcomings with this approach:
The static constructor has to be invoked through manual intervention before any Unit fields can be accessed
The NameOfField setter is public. In my case this is no problem, but it might be when applied in other scenarios. (I assume that the setter could be made private and invoked through further reflection, but I have not taken the time to explore that path further.)
... ?
Either way, maybe this solution can be of help to someone else than me.