So I stumbled upon the following:
Console.WriteLine(currentRow["Projekt"]);
Console.WriteLine($"{currentRow["Projekt"]}");
Console.WriteLine($"{(string)currentRow["Projekt"]}");
With the output:
> Data that i want
> Namespace.ExcelDataField
> Data that i want
Where ExcelDataField is obviously a class I wrote to help me read data out of an excel sheet. I tried to implement this to resemble VBAs DAO access with MoveFirst/Next and always expose 1 row of data (currentRow).
I used a class ExcelDataField to encapsulate the data coming out of my excel sheet because the type will be dynamic when reading.
public class ExcelDataField<T>
{
private Excel.Range m_XlRange;
private int m_Row;
private int m_Col;
public T Data
{
get
{
return (T)(this.m_XlRange.Cells[this.m_Row, this.m_Col] as Excel.Range)?.Value2;
}
set
{
this.m_XlRange.Cells[this.m_Row, this.m_Col] = value;
}
}
public ExcelDataField(Excel.Range range, int row, int col)
{
this.m_XlRange = range;
this.m_Row = row;
this.m_Col = col;
}
public static implicit operator T(ExcelDataField<T> dataField)
{
return dataField.Data;
}
}
Currently I am assuming for testing purposes that all data can later easily be handled as a string so I made an overload of this class ExcelDataField : ExcelDataField<string> which is the class I am using to read an excel sheet into. in the example, I am just reading it back to console.
Everything works fine as long as I am not using interpolated strings which obviously don't find my implicit conversion. I tried to change ExcelDataField : ExcelDataField<string> to ExcelDataField : ExcelDataField<String> but both don't work.
In my understanding interpolated strings use the FormattableString type which doesn't have any implicit conversion from string or String only explicit.
My question would be can anyone explain in greater detail what exactly is going on here and is there a clean way for me to able to use interpolated strings?
It is fairly easy. $"{currentRow["Projekt"]}" is just the same as string.Format("{0}", currentRow["Projekt"]). On the object instance provided by currentRow["Projekt"], the ToString method is called. The default implementation on object is that it returns the type name.
So basically all you have to do is to override that behavior. You can do that by overriding the ToString method:
public override string ToString()
{
return dataField.Data?.ToString();
}
Interpolated strings will either be compiled into a string.Format(...) expression, or compiled into a wrapper class FormattableString that internally uses string.Format(...)
Here's a rundown of the options considered for each such parameter:
Does the IFormatProvider given to string.Format(...) return a ICustomFormatter when asked? If yes then consult ICustomFormatter.Format for each value first.
Does the type of the parameter value implement IFormattable? If yes, then IFormattable.ToString is called
If no, then the .ToString() method is called directly on the value
So in your case, your best option is probably to just override ToString().
The exact code (at least in reference source) is inside StringBuilder, found here: StringBuilder.cs, line 1441 - AppendFormatHelper method.
Related
REMARK after rethinking my issue.
Though the best solution for my exact example with WriteData method was proposed by #Dogu Arslan, the issue in question's title was actually solved by #InBetween and #Fabio. I. e. for my exact example with WriteData method it is better to move the conversion logic out of WriteData method, but to abstract the logic from unrelated types it is better to use proposed overloading. So all the three answers are helpful for me.
I already have read the following similar questions - 1, 2, and others - but not have come with something suitable solution in my case.
My case is: I have the following simple method. The important part is the line with commentary and the "source" parameter. The rest part is not so important and serves only to show that there is an "operation" from the question's title.
void WriteData(
int count,
int currentIndex,
List<byte> source,
StreamWriter sw,
string fileName)
{
var countToWrite = count - currentIndex;
if (countToWrite == 0)
return;
if (sw == null)
sw = new StreamWriter(GetFullPath(fileName));
//---------- Source's elements must be converted to string.
var dataToWrite =
source.GetRange(currentIndex, countToWrite)
.Select(x => Convert.ToString(x));
StringBuilder sb = new StringBuilder();
foreach (var item in dataToWrite)
sb.AppendLine(item);
sw.Write(sb.ToString());
}
For now I want the "source" parameter to be list with bytes, or doubles, or strings. Have I write three copies of WriteData method with only single change - the type of list in "source"? Or there is a better approach?
I tried type constraint, but to what type to constrain?
I tried to check the type and to throw exceptions if it is not in my type list (byte, double, string). But exceptions work only at run-time, and I want it to work in compile-time.
For now I have to restrict myself with run-time type checking as temporary solution, but, as I mentioned before, it is not suitable in perspective.
Why not using overload methods with one "hided" actual solution
public void WriteData(List<byte> source) { WriteData<byte>(source); }
public void WriteData(List<double> source) { WriteData<double>(source); }
public void WriteData(List<string> source) { WriteData<string>(source); }
private void WriteData<T>(List<T> source)
{
// Your actual implementation
}
In private method you can check types and throw exception when wrong type is given, in case you want "protect" from making private method public by "mistake".
The best solution is to publicly expose the needed overloads and then delegate implementation to a private generic method:
public void WriteData( , , List<string> source, , ) { WriteData<string>(...); }
public void WriteData( , , List<byte> source, , ) { WriteData<byte>(...); }
public void WriteData( , , List<double> source, , ) { WriteData<double>(...); }
private void WriteData<T>( , , List<T> source, , )
{
Debug.Assert(typeof(T).Equals(typeof(string)) ||
typeof(T).Equals(typeof(byte)) ||
typeof(T).Equals(typeof(double)));
...
}
One thing you could do is to remove the string conversion responsibility to another class altogether.ie. StringConverter class which would have overloaded constructors that would take these different input types to convert them to string and provide a method that returns a string. That way even if you extend in future the types you support you would not need to change this method here in your example, all of that would be transparent behind you string converter class. The checks will also be compile time because string converter class would take the input through its constructor. Yes this would mean everytime you want to call WriteData method you would need to instantiate a new StringConverter object but C# does not provide type constraints on the level you ask out of the shelf.
I am working with someone else's code and trying to make some modifications. So what I'm needing to do is take the following:
RemoteFileDP remoteFile = new DPFactory().CreateRemoteFileDP(configData);
And change it so that remoteFile can equal what is in a string variable. To further explain let me give some more of the code:
ConfigDP configData = new ConfigDP();
So the statement above is executed before the remoteFile statement and ConfigDP is has two classes above it (abstract Config and then its base: abstract ConfigBase). DP is also the child of two abstract classes above it (abstract RemoteFile and abstract RemoteFileBase).
From my understanding remoteFile is the result of data extracted from a database query, stored into a list or a Hashtable (sorry just an intern so I'm working through this).
The reason I need remoteFile to accept a string value is because there are MANY methods that utilize the information in remoteFile and I would like to avoid having to create a WHOLE BUNCH of overloaded methods that accept a string value instead of RemoteFileDP remoteFile.
So if I can take a string value like:
string locationDirectory;
which is passed in from another method and then have something similar to the following:
RemoteFileDP remoteFile = locationDirectory;
then all other methods using remoteFile will not have to be overloaded or changed.
Sorry for all the detail but this is my first time posting so I hope I provided enough information. I did look at C# Convert dynamic string to existing Class and C#: Instantiate an object with a runtime-determined type and wrote the following code:
RemoteFilesDP remoteFile = (RemoteFileDP)Activator.CreateInstance(typeof(RemoteFileDP), locationDirectory);
However I keep getting a "MissingMethodException" error that the constructor for RemoteFileDP is not found but I do have the constructor as seen below:
public RemoteFileDP()
{
} //end of RemoteFilePlattsDP constructor
Thank you ahead of time for your assistance!
If you don't wish to modify the source project that RemoteFileDP lives in (or can't) you could write an extension method such as below:
public static RemoteFileDP ConvertToRemoteFileDP(this string location)
{
// Somehow create a RemoteFileDP object with your
// location string and return it
}
That way you could run the line of code you want:
RemoteFileDP remoteFile = locationDirectory;
With a slight modification as follows:
RemoteFileDP remoteFile = locationDirectory.ConvertToRemoteFileDP();
Would this allow you to solve your problem?
Although I like the idea of a constructor accepting a string more, you could define an implicit or explicit conversion operator between RemoteFileDP and string:
class RemoteFileDP
{
....
public static implicit operator RemoteFileDP(string locationDictionary)
{
//return a new and appropiately initialized RemoteFileDP object.
//you could mix this solution with Anna's the following way:
return new RemoteFileDP(locationDictionary);
}
}
This way you could actually write:
RemoteFileDP remoteFile = locationDirectory;
or, if the conversion operator were to be explicit:
RemoteFileDP remoteFile = (RemoteFileDP)locationDirectory;
Still I insist, Anna Lear's solution is better as implicit or explicit conversion doesn't really seem to be the best fit for this kind of case. For instance, if the conversion can fail due to an invalid locationDictionary value then I wouldn't recommend this path. If the conversion is always succesful no matter what value locationDictionary is (barring null) then it could be a valid solution to your problem.
I'm just putting it on the table as I think you might find it useful to know about explicit and implicit conversions in C#, in case you didn't already.
You're missing a constructor that takes a string as a parameter. Try your code with
public RemoteFileDP(string locationDirectory)
{
// do stuff with locationDirectory to initialize RemoteFileDP appropriately
}
Of course, if you do that, why not just call the constructor directly?
RemoteFileDP remoteFile = new RemoteFileDP(locationDirectory);
I am simplifying my code (I like to write the least amount of lines per function performed) and I often come across the lengthy process of data validation. So decided to write a Validate function, in pseudocode:
public static bool Validate(string input, out object output){
// try to parse data
try {
(TypeOf(object)) output = new (TypeOf(object));
output = (TypeOf(object)).Parse(input);
return true;
} catch {
return false;
}
}
So if I use in my code to validate several text boxes, it looks nice and very readable:
double var1;
Int32 var2;
byte var3;
if (!Validate(txtDouble.text, var1)) return "Error validating a Double";
if (!Validate(txtInt32.text, var2)) return "Error validating a Int32";
if (!Validate(txtByte.text, var3)) return "Error validating a byte";
// else all data is valid, continue
Process(var1, var2, var3)
I could create a static class Validate and overload for each type, but since I am planning on using on types that include the Parse method, it seems to me that there should be a way of implementing the above function... I just don't know what I am looking for. An interface keeps coming to my mind, but failing at implementing.
Thanks!
The framework providers already wrote your function for you, it's called TryParse. There is no generic nature to it, but it's called the exact same way you're calling Validate. Might as well use what's already there.
double var1;
if (!double.TryParse(input, out var1)) return "Invalid input";
The method is available for your double, int, float, char, DateTime, etc.
You're better off creating a static class with overloads (that call TryParse instead of Parse for the various types involved. The list is fairly short and your only other options will be convoluted.
Or you could just call the appropriate version of TryParse directly in your code. If you aren't inserting any additional validation (hence the need for your own validation class), then it won't be any more verbose than your pseudocode.
You could use something like this (it uses reflection):
private static void Test()
{
var r1 = TryParse("23", typeof(int));
var r2 = TryParse("true", typeof(bool));
}
private static bool TryParse(string valueToParse, Type type)
{
//there are more then one TryParse method and we need the one with 2 parameters
var method = type.GetMethods().Where(m => m.Name == "TryParse" && m.GetParameters().Count() == 2).Single();
var instance = Activator.CreateInstance(type); //create instance of the type
var result = method.Invoke(null, new object[] { valueToParse, instance });
return (bool)result;
}
but it's really fancy code (maybe there is a chance to write it a bit better;) ) and I would never use it.
As Anthony Pegram suggested you should create few overloads methods with TryParse - it's much cleaner and better solution.
If I have (in .NET/C#) for instance a variable of type long I can convert it to a formatted string like:
long value = 12345;
string formattedValue = value.ToString("D10"); // returns "0000012345"
If I specify a format which isn't valid for that type I get an exception:
long value = 12345;
string formattedValue = value.ToString("Q10"); // throws a System.FormatException
Question: Is there a way to check if a format specifier is valid (aside from trying to format and catching the exception) before I apply that format, something like long.IsFormatValid("Q10")?
Thanks for help!
I've not tried this but I would think you could create an extension method such as:
namespace ExtensionMethods
{
public static class MyExtensions
{
public static bool IsFormatValid<T>(this T target, string Format)
where T : IFormattable
{
try
{
target.ToString(Format, null);
}
catch
{
return false;
}
return true;
}
}
}
which you could then apply thus:
long value = 12345;
if (value.IsFormatValid("Q0"))
{
...
Rather than creating a check for that I'd suggest that it might be better that the developers reads the documentation to find out what's allowed where.
However, if there is a problem with a lot of typos being made, I suppose you could write a lookup table from the information on that page. Though that could just give you a false sense of security in that you'd get people making mistakes between valid format specifiers (writing an f but they meant e etc).
Edited to remove confused bit about TryParse/Parse.
I'm writing a tool that interfaces with an API for another piece of software. Part of my tool will need to generate reports about the various objects found through the API, and I want these reports to contain simple strings that identify each object. By default I plan to use ToString() to generate the string for each object. However, not surprisingly I've found that the default ToString() implementations in this API aren't to descriptive.
Initially I was thinking of doing something like the code below with a long Switch statement. Although this would most likely become unmanageably long.
public string GetAPIObjectDescrition(object obj)
{
Type t = obj.GetType();
Switch(t)
{
Case typeof(SomeAPIType):
SomeAPIType x = (SomeAPIType)obj;
return x.SomeProperty;
Case typeof(SomeOtherAPIType):
SomeOtherAPITypex = (SomeOtherAPIType)obj;
return x.SomeOtherProperty;
default:
return x.ToString();
}
}
Next I tried using extension methods (see the code below). CustomObjectDescription() worked as expected, but when I tried to call ToString() it just returns the default ToString() results. I've never used extension methods before so I could be completely off base thinking something like this is even possible.
I can't guarantee that there will be a CustomObjectDescription() extension for every Type encountered in the API, so if I take this route I would end up having to use reflection each time to check if the current object has a GetObjectDescription() extension. I'd like to avoid using reflection if at all possible.
public static class APIObjectDescriptionExtensions
{
public static string ToString(this APIObject element)
{
return "ElementName = " + element.Name + " ElementID =" + element.Id.IntegerValue.ToString();
}
public static string CustomObjectDescription(this APIObject element)
{
return "ElementName = " + element.Name + " ElementID =" + element.Id.IntegerValue.ToString();
}
}
Does anyone have any other suggestions on how I should approach this problem? I'd prefer a solution where the code for each API Type is independent from one another (no giant Switch statement).
Also if possible I'd like the description string code for one type to inherit to sub types unless those types have their own unique description string code.
I think there might be a better solution that involves creating custom TypeConverters or maybe overriding/extending System.Convert.ToString()?
Update
I think the example below might help clarify what I'm trying to do. Ultimately I want to be able to take any arbitrary class from this API, the Type of which is not known until run time, and generate a description string. If the Type has my custom extension method then it should be used, otherwise the code should fall back on plain old ToString().
public static string GetDataDescription(object o)
{
//get the type of the input object
Type objectType = o.GetType();
//check to see if a description extension method is defined
System.Reflection.MethodInfo extensionMethod = objectType.GetMethod("MyDescriptionExtensionMethod");
if (extensionMethod != null)
{
//if a description extension method was found returt the result
return (string)extensionMethod.Invoke(o, new object[] { });
}
else
{
//otherwise just use ToString();
return o.ToString();
}
}
This code above doesn't work though because extension methods aren't found by GetMethod().
You could provide a wrapper for each of the classes similar to this:
public class SomeAPITypeWrapper : SomeAPIType
{
public override string ToString()
{
return SomeProperty;
}
}
public class SomeOtherAPITypeWrapper : SomeOtherAPIType
{
public override string ToString()
{
return SomeOtherProperty;
}
}
This certainly allows for using base classes/sub classes as requested in your question. It also keeps it clean and within your object model itself instead of in a switch statement or helper class.
Did you try using another name other then ToString() in your extension class? I am not completely sure about extension methods either, but I am guessing the base.ToString was getting called instead of yours. Possibly making a ToDescription() extension method would yield better results.
If a given method call can be resolved by an instance method and an extension method, the instance method is given preference. So extension methods need to be named such that they don't have same names as methods in the extended type.
From the code above, it seems that you don't control the source of APIObject and its derivations. So your options are 'Introduce Foreign Method' and 'Introduce Local Extension'
I'd try foreign method (which is similar to C# extension methods).. not sure why you would need reflection though. If the extension method doesn't exist, it'd be a compile-time error. How are you consuming this method ?
Finally switch statements are not that bad... unless they are very long/need frequent changes/duplicated across locations.
I suggest making a Dictionary<Type,Converter<object,string>>. Then you can look for a custom stringizer, and if none is found, call ToString.
Note, the dictionary will check for an exact match on types, so if you want to handle subclasses you'll have to write some additional code to see whether base types are listed in the dictionary (hint: if you match a base class, or even if you don't, go ahead and add the actual derived type to the dictionary so you won't have to recurse through the inheritance tree again).
Note that you can build an "open delegate" for Object.ToString() which conforms to the Converter<object,string> contract and use that as a default, even store it in the dictionary, instead of special-casing the call to ToString.
You could defer all tostringing to a separate concern of your application. StatePrinter (https://github.com/kbilsted/StatePrinter) is one such API where you can use the defaults or configure depending on types to print.
var car = new Car(new SteeringWheel(new FoamGrip("Plastic")));
car.Brand = "Toyota";
then print it
StatePrinter printer = new StatePrinter();
Console.WriteLine(printer.PrintObject(car));
and you get the following output
new Car() {
StereoAmplifiers = null
steeringWheel = new SteeringWheel()
{
Size = 3
Grip = new FoamGrip()
{
Material = ""Plastic""
}
Weight = 525
}
Brand = ""Toyota"" }
and with the IValueConverter abstraction you can define how types are printer, and with the FieldHarvester you can define which fields are to be included in the string.