In relation to the question Get the name of parameters from a calling method and Finding the Variable Name passed to a Function in C# I'm still looking for a way to define theWhatDoesTheAnimalSay_WANTED
method: I want to know the name of the variable that's used as a parameter:
public class Farm
{
public readonly string Cow = "Muuuuhh";
public string Cat { get; set; }
public void MainFunction()
{
var dog = "WauWau";
var kiwi = new Bird("QueeeekQueeek");
Cat = "Miiiaaauuuu";
// This one works but looks kinda ugly and is cumbersome when used
WhatDoesTheAnimalSay(nameof(dog), dog);
WhatDoesTheAnimalSay(nameof(Cow), Cow);
WhatDoesTheAnimalSay(nameof(Cat), Cat);
WhatDoesTheAnimalSay(nameof(kiwi), kiwi);
WhatDoesTheAnimalSay_WRONG1(dog);
WhatDoesTheAnimalSay_WRONG2(dog);
WhatDoesTheAnimalSay_WANTED(dog);
WhatDoesTheAnimalSay_WANTED(Cow);
}
public void WhatDoesTheAnimalSay<T>(string name, T says)
{
MessageBox.Show("The " + name + " says: " + says);
// Shows i.e.: The dog says: WauWau
}
public void WhatDoesTheAnimalSay_WRONG1<T>(T says)
{
MessageBox.Show("The " + nameof(says) + " says: " + says);
// Shows: The says says: WauWau
}
public void WhatDoesTheAnimalSay_WRONG2<T>(T says, [CallerMemberName] string name = null)
{
MessageBox.Show("The " + name + " says: " + says);
// Shows: The MainFunction says: WauWau
}
public void WhatDoesTheAnimalSay_WANTED<T>(T says /*, ?????*/)
{
MessageBox.Show("The " /*+ ?????*/ + " says: " + says);
// Shows: The dog says: WauWau
}
}
// Just here to show it should work with a class as well.
public class Bird
{
public string Says { get; } //readonly
public Bird(string says) {
Says = says;
}
public override string ToString()
{
return Says;
}
}
In real life I need this while implementing the IXmlSerializable
interface in my classes with custom reader.Read...
and writer.Write....
methods.
So, unfortunately, I cannot introduce a new wrapper class, interface or change where the name of the animal or what it says is saved. Meaning it has to work with classes and with a plain string, int, decimal, ... variables, fields or properties as well.
In other words (not in a rude way): Don't change how are the animals defined, just change the WhatDoesTheAnimalSay_WANTED
method...
EDIT:
As some of you wanted to know a real use case for this example I'm giving you here an idea how I store & read data in an xml-file. The real Database object is of course way bigger and all sub-classes (like Fitter
) implement the IXmlSerializable
interface as well using the same extensions methods.
// This is the Database Class which stores all the data
public class Database : IXmlSerializable
{
// The list of all building sites managed
public List<BuildingSite> BuildingSites { get; set; }
// The list of all fitters working for the company
public List<Fitter> Fitters { get; set; }
private readonly int DatabaseVersion = 1;
// Write implementation of the IXmlSerializable inteface
public void WriteXml(XmlWriter writer)
{
// Writing all Data into the xml-file
writer.WriteElementInt(nameof(DatabaseVersion), DatabaseVersion);
writer.WriteElementList(nameof(BuildingSites), BuildingSites);
writer.WriteElementList(nameof(Fitters), Fitters);
}
public void ReadXml(XmlReader reader)
{
// Do the reading here
}
public XmlSchema GetSchema() { return null; }
}
public class XmlExtensions
{
// Writing a list into the xml-file
public static void WriteElementList<T>(this XmlWriter writer, string elementName, IEnumerable<T> items)
{
var list = items is List<T> ? items : items.ToList();
// The XML-Element should have the name of the variable in Database!!!
writer.WriteStartElement(elementName);
writer.WriteAttributeString("count", list.Count().ToString());
var serializer = new XmlSerializer(typeof(T));
list.ForEach(o => serializer.Serialize(writer, o, XmlHelper.XmlNamespaces));
writer.WriteEndElement();
}
public static void WriteElementInt(this XmlWriter writer, string elementName, int toWrite)
{
// The XMLElement should have the name of the variable in Database!!!
writer.WriteElementString(elementName, toWrite.ToString(CultureInfo.InvariantCulture));
}
// More here....
}
}
[CallerMemberName]
attribute which can do that. Something like[CallerParameterName]
.... – Glorianna