When dealing with custom exceptions, I usually inherit from Exception and then add some fields/properties to my exception class to store some additional info:
public class MyException : Exception
{
public int ErrorCode{get;set;}
public MyException()
{}
}
In the above example, the ErrorCode value is stored in the exception, meaning that I have to add it to and retireve if from the SerializationInfo object in the protected constructor and the overridden GetObjectData method.
The Exception class has a Data property, which according to MSDN:
Gets a collection of key/value pairs that provide additional user-defined information about the exception.
If I store the error code inside the Data, it will get serialised for me by the Exception class (according to Reflector), meaning that my exception class now looks like:
public class MyException : Exception
{
public int ErrorCode
{
get {return (int) Data["ErrorCode"];}
set {Data["ErrorCode"] = value;}
}
public MyException()
{}
}
This means that whilst there is a bit more work to do in dealing with the get/set of the error code (like dealing with casting errors and situations where the error code might not be in the dictionary), I don't have to worry about serialising/deserialising it.
Is this just two different ways of achieving the same thing, or does one way have any clear advantage(s) over the other (apart from those I've already mentioned)?
If you are bothering to create your own exception, you don't need the Data property. Data comes in useful when you want to store a bit of extra information in an existing exception class, but don't want to create your own custom exception class.
I would avoid using Data as it is not under your control e.g. some code somewhere might decide to overwrite the "ErrorCode" value. Instead use the propery and implement serialization. I use the following code to test all my custom exceptions to make sure I've implemented them properly.
public static void TestCustomException<T>() where T : Exception
{
var t = typeof(T);
//Custom exceptions should have the following 3 constructors
var e1 = (T)Activator.CreateInstance(t, null);
const string message = "message";
var e2 = (T)Activator.CreateInstance(t, message);
Assert.AreEqual(message, e2.Message);
var innerEx = new Exception("inner Exception");
var e3 = (T)Activator.CreateInstance(t, message, innerEx);
Assert.AreEqual(message, e3.Message);
Assert.AreEqual(innerEx, e3.InnerException);
//They should also be serializable
var stream = new MemoryStream();
var formatter = new BinaryFormatter();
formatter.Serialize(stream, e3);
stream.Flush();
stream.Position = 0;
var e4 = (T)formatter.Deserialize(stream);
Assert.AreEqual(message, e4.Message);
Assert.AreEqual(innerEx.ToString(), e4.InnerException.ToString());
}
Microsoft's own guidelines:
Do make exceptions serializable. An exception must be serializable to work correctly across application domain and remoting boundaries.
I would store it in the Data-property which sadly would let outside code modify the value without consent, or use solution 1 (in your example) but make it serializeable. In the end I would probably go for solution 1 so I can be sure that the value never changes.
You should go with the first solution. I can't see much value in the Data property, unless you plan to raise row Exception instances with attached infos.
If you have your own Exception type, then use properties instead: it's more clean and safe.
Related
I need to be able to make the XmlReader/XmlSerializer be ready to handle more than one possible value for an enum that it reads and properly translate it into the correct C# enum. But I cannot figure out how to do this.
Consider this LengthUnit enum (trimmed down to only 2 possible units for brevity)
public enum LengthUnit
{
Micron,
Millimeter,
}
My code writes and reads this just fine like this:
<CurrentUnit>Millimeter</CurrentUnit>
but reader code needs be able to handle either of two possible values: "Millimeter" or "mm" and properly translate it into LengthUnit.Millimeter So I need to be able to read either the above XML or the following:
<CurrentUnit>mm</CurrentUnit>
Unfortunately when I try to read in a file with the latter, the XmlReader throws an InvalidOperationException
Exception of type: 'System.InvalidOperationException' Message='Instance validation error: 'mm' is not a valid value for LengthUnit.'
I took at look the XmlEnum attribute to see if I could solve my problem with that, but it will only allow me to choose one name. No alternate
I did find this discussion about writing alternate element names but I cannot seem to apply it to reading different enum values.
Is this possible? How would I go about it. (Hell I'd even write my own custom [XmlEnumAttribute2] attribute if I could figure how.
[EDIT: Deserializer Code per request. ]
Multiple class types derive from this abstract class and add their own properties to be serialized in XML. I've not shown other members here. The key point to remember is that some of those derived classes use the LengthUnit enum and (for reasons not germane to this question), sometimes those LengthUnit values are persisted with short names instead of the full names.
I need to be able to handle that gracefully and I'd like to be able to handle it with out line-by-line handling of XML.
public abstract class SettingsBaseVm<T> : BaseVm where T : SettingsBaseVm<T>, new()
{
protected static T LoadImpl(string path, ILogger logger)
{
// Handle events so partial reads still work.
try
{
var events = new XmlDeserializationEvents
{
OnUnknownAttribute = (s, e) => logger.Warn($"UserSettings: Unknown attribute {e.Attr.Name}"),
OnUnknownElement = (s, e) => logger.Warn($"UserSettings: Unknown element {e.Element.Name}"),
OnUnknownNode = (s, e) => logger.Warn($"UserSettings: Unknown node {e.Name}"),
OnUnreferencedObject = (s, e) => logger.Warn($"UserSettings: UnreferencedObject")
};
using var xmlReader = XmlReader.Create(path);
xmlReader.MoveToContent();
var deserializer = new XmlSerializer(typeof(T));
var settings = deserializer.Deserialize(xmlReader, events) as T ?? throw new InvalidDataException(path);
settings.Log = logger; // So it can log errors
settings.FilePath = path;
settings.IsDirty = false;
return settings;
}
catch (Exception e) when (
e is ArgumentException ||
e is IOException ||
e is NotSupportedException ||
e is UnauthorizedAccessException ||
e is SecurityException ||
e is FormatException ||
e is XmlException
)
{
logger.Error(e);
return new T() { Log = logger, FilePath = path };
}
}
}
I have this class:
public class PlaylistMessageBindingModel
{
//Other non-important fields
public Decimal Duration { get; set; }
}
I am instantiating an object of this class and read values out of a database with a data reader:
while (innerReader.Read())
{
var playlistMsg = new PlaylistMessageBindingModel();
playlistMsg.Duration = (Decimal)reader["size_time"];
}
But when it hits the .Duration line of code, it throws an Exception:
An exception of type 'System.Exception' occurred in MyDll.dll but was not handled in user code
Additional information: size_time
The value column in the database is decimal(6, 3). I'm guessing it might have to do with the fact that the value coming out of the database is 0.000, but if that is the case, I'm not sure how to deal with that. I'd appreciate any observations.
Have you tried this?
while (innerReader.Read())
{
var playlistMsg = new PlaylistMessageBindingModel();
playlistMsg.Duration = reader.GetDecimal["size_time"];
}
Also very useful SQL Server Data Type Mappings
This is what happens when you stare at your own code for too long...
I failed to notice a subtle difference in my reader objects. Above this section of code, I have instantiated a reader called reader. Further down the code, I instantiated innerReader. So when I was trying to set the duration, I have while (innerReader.Read()) and inside that code block I'm trying playlistMsg.Duration = (Decimal)reader["size_time"]; but it should be (Decimal)innerReader["size_time"]. After changing the code, I got my intended result.
I am trying to serialse a fingerprint FMD to XML using the code below, but get an error:
Error: DPUruNet.DataResult`1[DPUruNet.Fmd] cannot be serialized
because it does not have a parameterless constructor.
public void storePrint(DataResult<Fmd> resultConversion)
{
//store fingerprint as byte and insert to server------------
using (StreamWriter myWriter = new StreamWriter("test.txt", false))
{
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(resultConversion.GetType());
x.Serialize(myWriter, resultConversion);
}
MessageBox.Show("Fingerprint Stored!");
//------------------------------------------------------------
}
private void OnCaptured(CaptureResult captureResult)
{
try
{
// Check capture quality and throw an error if bad.
if (!_sender.CheckCaptureResult(captureResult)) return;
count++;
DataResult<Fmd> resultConversion = FeatureExtraction.CreateFmdFromFid(captureResult.Data, Constants.Formats.Fmd.ANSI);
SendMessage(Action.SendMessage, "A finger was captured. \r\nCount: " + (count));
if (resultConversion.ResultCode != Constants.ResultCode.DP_SUCCESS)
{
_sender.Reset = true;
throw new Exception(resultConversion.ResultCode.ToString());
}
preenrollmentFmds.Add(resultConversion.Data);
//--------------------CALL METHOD
storePrint(resultConversion);
//
The class DataResult is being referenced, so I can not alter it
UPDATE
If you don't have access to the DataResult<T> class, then you might have to take a slightly different approach and wrap this class with a different, serializable one. You can find a full example here:
How can I XML Serialize a Sealed Class with No Parameterless Constructor?
Previous Answer
The error is clear; you just need to add a parameterless constructor to the DataResult<T> class:
public class DataResult<T>
{
// Add a default constructor (public visibility, no parameters)
public DataResult()
{
// You can still define a method body if you wish,
// no restrictions there. Just don't do anything that
// could jeopardize the (de)serialization.
}
}
As for the implications of adding a default constructor, without knowing what
FeatureExtraction.CreateFmdFromFid(...)
is doing to create the DataResult<Fmd>, it would be impossible to know whether it would cause any issues.
Thanks to Cory, that is a useful answer, however in this example there is another way of serializing using
tempFingerPrint = Fmd.SerializeXml(resultConversion.Data);
this is specific to the Digital Persona SDK
I'm trying to implement a custom formatter using the .NET IFormatter interface.
After a couple of hours of search, I just found a very basic sample which unfortunately doesn't include recursion. I also tried with Reflector to look at BinaryFormatter and SoapFormatter, but they are rather complex.
My question is:
Should I implement recursion myself, or there's something I've missed in FormatterServices?
Following my code:
public void Serialize(Stream serializationStream, object graph)
{
// Get fields that are to be serialized.
MemberInfo[] members = FormatterServices.GetSerializableMembers(graph.GetType(), Context);
// Get fields data.
object[] data = FormatterServices.GetObjectData(graph, members);
// Write class name and all fields & values to file
StreamWriter sw = new StreamWriter(serializationStream);
string accumulator = string.Empty;
for (int i = 0; i < data.Length; ++i)
{
// Skip this field if it is marked NonSerialized.
if (Attribute.IsDefined(members[i], typeof(NonSerializedAttribute)))
continue;
FieldInfo field = (FieldInfo)members[i];
if (field.FieldType.IsPrimitive)
{
}
else //TODO: What should I do here?
}
sw.Close();
}
If by recursion you mean traversing through the object tree then yes, it up to you when you implement your own IFormatter.
Simply check if the value of the property is not null and if it is implementing IFormatter interface. If it is then just call it and use the value it returns.
If not then it is up to you again: you may throw an exception saying that IFormatter must be implemented, or just fall-back to some sort of default formatter (XML or Binary one).
The recursion per se is tricky. When, let's say, the object references itself, you need to be smart enough to handle this situation and not to end up with the infinite loop:
public class A {
public object SomeProperty { get; set; }
}
var a = new A();
a.SomeProperty = a;
There are a number of tricky aspects in implementing formatters, like what if two properties are actually reference the same object? Will you serialize/format it twice or just once and keep the information about these references somehow?
You don't probably need this if you want just one-way serialization, but if you want to be able to restore the object it might be important...
I'm reading data in from a file and creating objects based on this data. The data format is not under my control and is occasionally corrupt. What is the most appropriate way of handling these errors when constructing the objects in C#?
In other programming languages I have returned a null, but that does not appear to be an option with C#.
I've managed to figure out the following options, but I would appreciate advice from more experienced C# programmers:
Option 1. Read the file inside the constructor and throw an exception when the source data is corrupt:
try
{
obj = Constructor(sourceFile);
... process object ...
}
catch (IOException ex)
{
...
}
Option 2. Create the object, then use a method to read data from the source file:
obj = Constructor();
obj.ReadData(sourceFile);
if (obj.IsValid)
{
... process object ...
}
or possibly throw exceptions on error:
obj = Constructor();
try
{
obj.Read(sourceFile);
... process object ...
}
catch
{
...
}
Option 3. Create the object using a static TryParse method:
if (ObjClass.TryParse(sourceFile, out obj))
{
... process object ...
}
and if so, should I implement option 3 internally using option 1?
public static bool TryParse(FileStream sourceFile, out ObjClass obj)
{
try
{
obj = Constructor(sourceFile);
return true;
}
catch (IOException ex)
return false;
}
I would do something along the lines of option 3):
class ObjectClass
{
protected ObjectClass(...constructor parameters your object depends on...)
{
}
public static ObjectClass CreateFromFile(FileStream sourceFile)
{
.. parse source file
if (parseOk)
{
return new ObjectClass(my, constructor, parameters);
}
return null;
}
}
And then use it like this:
ObjClass.CreateFromFile(sourcefile);
In general the constructor should take as parameters all properties which essentially define the class. Doing heavyweight calculations (like parsing a file) is best left to factory methods as it is usually not expected for the constructor to perform complex and potentially long running tasks.
Update: As mentioned in comments a better pattern is this:
public static ObjectClass CreateFromFile(FileStream sourceFile)
{
.. parse source file
if (!parseOk)
{
throw new ParseException(parseErrorDescription);
}
return new ObjectClass(my, constructor, parameters);
}
public static bool TryCreateFromFile(FileStream sourceFile, out ObjectClass obj)
{
obj = null;
.. parse source file
if (!parseOk)
{
return false;
}
obj = new ObjectClass(my, constructor, parameters);
return true;
}
I would not put anything into a constructor that might throw an exception - except for if something goes really wrong.
If your constructor has a possible return value other than a valid object, you should encapsulate it.
The safest way would probably be to create a factory method (public static function in the class that accepts a file reference and returns a new instance of the class or null). This method should first validate the file and its data and only then create a new object.
If the file data has a simple structure, you can first load it into some local variable and construct the object with this data.
Otherwise, you can still decide - inside of your factory method - if you rather want to try / catch the construction or use any of the other points mentioned above.
Both Options #1 and #3 are good choices and common in the .Net framework. It's also common to provide both for the same type. Consider Int32.TryParse and Int32.Parse. Providing both gives developers a bit more flexibility without detracting from the integrity of the type.
I would strongly advise you to avoid #2. This pattern forces both the type author and type consumer to handle instances of the type in multiple states
Constructed but not fully initialized
Initialized and valid
Initialized and invalid
This puts a burden on every consumer to deal with instances being in all different states (even if the response is to just throw). Additionally it forces a non-standard pattern on consumers. Developers have to understand your type is special and that it needs to be constructed and then initialized. It goes against the standard way objects are created in .Net.
Note for #3 though I would approach it a bit different. The exception form should be implemented in terms of the try form. This is the standard pattern when providing both options to the user. Consider the following pattern
class MyType {
struct ParsedData {
// Data from the file
}
public MyType(string filePath) : this(Parse(filePath)) {
// The Parse method will throw here if the data is invalid
}
private MyType(ParsedData data) {
// Operate on the valid data. This doesn't throw since the errors
// have been rooted out already in TryParseFile
}
public static bool TryParse(string filePath, out MyType obj) {
ParsedData data;
if (!TryParseFile(filePath, out data)) {
obj = null;
return false;
}
obj = new MyType(data);
return true;
}
private static ParsedData Parse(string filePath) {
ParsedData data;
if (!TryParseFile(filePath, out data)) {
throw new Exception(...);
}
return data;
}
private static bool TryParseFile(string filePath, out ParsedData data) {
// Parse the file and implement error detection logic here
}
}
From Microsoft Constructor Design Guidelines (MSDN),
Do throw exceptions from instance constructors if appropriate.
Constructors should throw and handle exceptions like any method. Specifically, a constructor should not catch and hide any exceptions that it cannot handle.
Factory Method is not the right way to approach this problem. See Constructors vs Factory Methods
From Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries
5.3 Constructor Design
Consider using a static factory method instead of a constructor if the
semantics of the desired operation do not map directly to the construction
of a new instance, or if following the constructor design guidelines
feels unnatural.
Do throw exceptions from instance constructors if appropriate.
.NET BCL implementations do throw exceptions from constructors
For example, the List Constructor (Int32), throws an ArgumentOutOfRangeException when the capacity argument of the list is negative.
var myList = new List<int>(-1); // throws ArgumentOutOfRangeException
Similarly, your constructor should throw an appropriate type of exception when it reads the file. For example, it could throw FileNotFoundException if the file does not exist at the specified location, etc.
More Information
Code Contracts
Throwing exceptions from constructor in .Net
Throwing ArgumentNullException in constructor?
Constructor parameter validation in C# - Best practices
All these solutions work, but as you said, C# doesn't allow to return null from a constructor. You either get an object or an exception. Since this is the C# way to go, I wouldn't choose option 3, because that merely mimics that other language you're talking about.
Lots of people [edit] among which is Martin, as I read in his answer :) [/edit] think it is good to keep your constructor clean and small. I'm not so sure about that. If your object is of no use without that data, you could read in the data in the constructor too. If you want to construct the object, set some options, and then read the data (especially with the possility to try again if the read fails), a separate method would be fine as well. So option 2 is a good possibility too. Even better maybe, depending mainly on taste.
So as long as you don't choose 3, choose the one you're the most comfortable with. :)