Declare and add a single element above the try, and then add the rest inside. Since you're specifically worried about duplicate keys, adding the first key/item gets you the type without the risk.
EDIT: I think just inferring the type, without adding the first element, is slightly better. While the usage is a bit cumbersome, it'll make it easier to add remaining elements (as opposed to clearing the dictionary, and then adding - or having to add everything after the 1st one - really only cleanly doable if you're consuming an IEnumerable).
var dict1 = InferDictionary(new { Value1 = 0, Value2 = "string" }, new DataItem());
try {
data1.AddToDictionary(
dict1,
dim => new { Value1 = dim.Val1, Value2 = dim.Val2 }
);
} catch ... {
...
}
static IDictionary<TKey, TValue> InferDictionary<TKey, TValue>(TKey keyPrototype, TValue valuePrototype) {
return new Dictionary<TKey, TValue>();
}
Or, create a convenience function to catch the exception for you:
var dict1 = TryCatch(
() =>
data1.ToDictionary(dim => new {
Value1 = dim.Val1,
Value2 = dum.Val2
}
, (ArgumentException ex) => {
Console.WriteLine("Duplicate values in Data1 {0}", ex);
// throw(ex) works as well, and shouldn't screw the callstack up much
// But I happen to like making it explicit
return false;
}
);
static TResult TryCatch<TResult, TException>(Func<TResult> @try, Func<TException, bool> @catch) where TException : Exception {
try {
return @try();
} catch (Exception ex) {
TException tEx = ex as TException;
if (tEx != null && @catch(ex)) {
// handled
} else {
throw;
}
}
}
The caveat of this is that you can't call TryCatch<,>
in the "natural" ways:
// Not enough info to infer TException
var d = TryCatch(() => DoStuff(), ex => true);
// Can't infer only TResult
var d = TryCatch<ArgumentException>(() => DoStuff(), ex => true);
which, since you can't specify TResult
, forces you into the somewhat odd syntax of declaring TException
on the lambda:
var d = TryCatch(() => DoStuff(), (ArgumentException ex) => true);