Reputation: 303
I'm having difficulty accessing the values of the data property of the Exception class.
try
{
string strReasonCode = String.Empty;
string strReasonDescription = String.Empty;
string strDuration = String.Empty;
string strActive = String.Empty;
if (ReasonCodeDT.Rows.Count != 1)
{
string strPracticeID = PracticeID.ToString();
string PracticeName = getSingleStringResultFromSQL("SELECT @result = PracticeName FROM Practice WHERE PracticeID = /'" + strPracticeID + "/'");
string RecordCount = ReasonCodeDT.Rows.Count.ToString();
int UserID;
Int32.TryParse(au.UserID, out UserID);
Exception ex = new Exception("Database Returned " + RecordCount + " Records for ReasonCodeID " + ReasonCodeID + " for Practice " + PracticeName + " (" + strPracticeID + ")");
ex.Data.Add("UI Error Message", "Whoops! Something went wrong there. Please call (555)555-5555" +
"and notify them something is wrong with the Encounter Reason: " + ReasonCodeID);
throw ex;
}
else
{
}
}
catch
{
pnlError.Visible = true;
lblErrorMessage.Text = ex.Data["UI Error Message"];
}
This gives me a compiler error message:
Error 117 Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?)
All the references I can find access that information by using foreach
loops specifying the type as DictionaryEntry
but that isn't necessary/ desirable for this instance:
How do I retrieve a single item from that dictionary?
UPDATE
In reference to @dbc's suggestion of creating a custom exception class, here is a link providing more detail as to why I didn't do so.
https://blogs.msdn.microsoft.com/jaredpar/2008/10/20/custom-exceptions-when-should-you-create-them/
Feel free to comment as to why an exception class would be better than using the data property of the base exception class.
Upvotes: 3
Views: 1950
Reputation: 116711
Exception.Data
is an an untyped IDictionary
:
public virtual IDictionary Data { get; }
Therefore the get
and set
accessors return and take a value of type object
, which you must cast or convert to your desired type, e.g.:
public const string ExceptionMessageKey = "UI Error Message";
lblErrorMessage.Text = ex.Data[ExceptionMessageKey]?.ToString();
(Where ?.
is the c# 6.0 null conditional operator). Or alternatively:
lblErrorMessage.Text = ex.Data[ExceptionMessageKey] as string;
As an aside, if you are more familiar with the generic IDictionary<TKey, TValue>
interface, take note of the following difference. When using an untyped IDictionary
and accessing a key that does not exist, the getter documentation states:
Property Value
The element with the specified key, or null if the key does not exist.
In contrast, the IDictionary<TKey, TValue>
documentation states that a KeyNotFoundException
will be thrown when the key is not found. There is no TryGetGetValue()
for IDictionary
.
Sample .Net fiddle here.
Update
Also, is the const
keyword mandatory or just best practice in this case? Use of const
here is purely good practice. Since you are going to getting and setting exception details in your Data
dictionary with standardized keys, it's a good idea to centralize the actual values of those keys in one place in your code which can be used by both producers and consumers of your Exception
, e.g. a static constants class:
public static class Constants
{
public const string ExceptionMessageKey = "UI Error Message";
}
Also, why must one declare the string constant before using the data property of the exception class? -- it isn't necessary. I did that only to make the value of ExceptionMessageKey
be a public constant.
When I use the null conditional operator with the syntax you outline, I get a compile time error saying "Syntax Error ':' expected". -- then you are probably using a version of c# earlier than 6.0. If so you can use the following older syntax instead:
var value = ex.Data[Constants.ExceptionMessageKey];
string text = value == null ? null : value.ToString();
Finally, as mentioned in Handling and throwing exceptions in .NET it's good practice to throw some more appropriate derived type of Exception
. You could choose a common, pre-existing type such as ApplicationException
or define your own, in which case the "UI Error Message" could be made a property of the exception rather than an entry in the Data
dictionary.
Upvotes: 4