我必须查询一些可能为空的数据,并在访问它们时引发异常。假设我必须查询一个整数字段
int[] numbers = { 0, 1, 2, 3, 4 };
int targetNumber = numbers[10];
我必须将int targetNumber = numbers[10];
包装到try catch块中,因为索引将抛出超出范围的异常。
int targetNumber;
try
{
targetNumber = numbers[10];
}
catch (Exception)
{
targetNumber = 7; // default value for index 10
}
当加载多个字段时,这将是非常低效的。我正在寻找一种使用这种方式的方法
int targetNumber = numbers[10] || 7;
引发异常时,应用程序将不会崩溃并采用默认值。通过这种方法,我可以避免多个try catch块。
整数数组只是一个例子。我在考虑带有复杂对象的复杂集合。因此,外部库可以使我访问ICollection
类型的集合,并且可以使用字符串(键)访问这些集合。如果密钥不存在,则会引发异常。
因此,当使用
访问这些文件时string value = collection["myKey"]
我想将其扩展到
string value = collection["myKey"] || "MyDefaultValueToTakeIfSomethingFailed";
答案 0 :(得分:9)
关于最近,我可以想到的是,如果要测试数组的长度以确保其包含索引10(第11个项目)的元素,请使用内联
declare @r table(Product_Code varchar(20),Product_Description varchar(20),Min_Range decimal(10,2),Max_Range decimal(10,2),Interest_Rate decimal(10,2));
insert into @r values('2000-0100','Saving',0,4999.99,0.01),('2000-0100','Saving',5000,9999.99,0.02),('2000-0100','Saving',10000,49999.99,0.03),('2000-1111','Senior Savings',0,4999.99,0.03),('2000-1111','Senior Savings',5000,9999.99,0.04),('2000-1111','Senior Savings',10000,49999.99,0.05);
declare @b table(BalanceDate date,Balance decimal(10,2),Product_Code varchar(20),Product_Description varchar(20),AccountNo int);
insert into @b values('20190228',19447.83,'2000-0100','Saving',3059123),('20190227',19557.61,'2000-0100','Saving',3059123),('20190226',19976.01,'2000-0100','Saving',3059123),('20190225',20530.91,'2000-0100','Saving',3059123),('20190228',12345,'2000-1111','Senior Savings',4059123),('20190227',5456,'2000-1111','Senior Savings',4059123),('20190226',9999,'2000-1111','Senior Savings',4059123),('20190225',7893,'2000-1111','Senior Savings',4059123);
select b.AccountNo
,b.Product_Code
,b.Product_Description
,b.BalanceDate
,b.Balance
,r.Min_Range
,r.Max_Range
,r.Interest_Rate
,case when b.Balance > r.Max_Range
then r.Max_Range - r.Min_Range
else b.Balance - r.Min_Range
end as Split_Balance
,r.Interest_rate * case when b.Balance > r.Max_Range
then r.Max_Range - r.Min_Range
else b.Balance - r.Min_Range
end as Split_Balance_Interest
from @b as b
join @r as r
on b.Product_Code = r.Product_Code
and b.Balance > r.Min_Range
order by b.AccountNo
,b.BalanceDate;
不是存在空引用,而是您的数组长度不足以提供索引10(ArrayIndexOutOfBoundsException)
基本规则是“如果数字数组的长度大于X的X处的检索元素”-如果有11个或更多的元素,则检索[10]将会成功
如果您使用的是可为空的内容,那么您还可以使用??运营商提供默认值
int targetNumber = numbers.Length > 10 ? numbers[10] : 7;
您不能完全避开这两个不同的例外。 ArrayIndexOutOfBounds和NullReferenceexception-长度测试可防止越界,然后可以使用??防止空值(可能是元素10为空或数组不够长)。
答案 1 :(得分:7)
您可以使用LINQ:
string targetString = (strings.Length > 10 ? strings[10] : null) ?? "defaultstring";
int targetNumber = numbers.Cast<int?>().ElementAtOrDefault(10) ?? 7;
将使您从中选取的元素为空,这将使Cast
返回ElementAtOrDefault
,以防您未击中条目。最后,如果合并表达式为null
,则空合并运算符??
将使表达式成为默认值。
如果数组包含引用类型或可为空的值类型,则可以不进行强制转换:
null
在这种情况下,您可以期望string targetString = strings.ElementAtOrDefault(10) ?? "default";
在基础对象中检查ElementAtOrDefault
和IList<T>
,因此它不会在此处迭代整个数组,而是评估其长度并选择直接从其索引中获取价值。
答案 2 :(得分:1)
您可以使用适用于各种数据类型的具有相同签名的扩展方法来构建taket。编译器将在编译时选择合适的编译器,因此在运行时性能将达到最佳。
phoneNumber?.trimmingCharacters(in: .symbols).count
用法示例:
public static class GetValueExtensions
{
public static T GetValue<T>(this T[] source, int key, T defaultValue) // Array
{
if (key >= 0 && key < source.Length) return source[key];
return defaultValue;
}
public static T GetValue<T>(this IList<T> source, int key, T defaultValue) // List
{
if (key >= 0 && key < source.Count) return source[key];
return defaultValue;
}
public static TValue GetValue<TKey, TValue>( // Dictionary
this IDictionary<TKey, TValue> source, TKey key, TValue defaultValue)
{
if (source.TryGetValue(key, out TValue value)) return value;
return defaultValue;
}
}
如果要避免一次又一次重复默认值,则可以使用:
var s = new string[] { "Foo", "Bar" }.GetValue(5, "Empty"); // Returns "Empty"
var c = new List<char> { 'a', 'b', 'c' }.GetValue(2, '_'); // Returns 'c'
var b = new Dictionary<int, bool>() { { 1, false }, { 2, true } }
.GetValue(13, true); // Returns true
用法示例:
public static Func<int, T> GetGetter<T>(this T[] source, T defaultValue)
{
return (key) =>
{
if (key >= 0 && key < source.Length) return source[key];
return defaultValue;
};
}