我来自PHP和Javascript的Wild Wild West,您可以从函数中返回任何内容。虽然我不喜欢缺乏问责制,但我在努力保持代码“完美”方面也遇到了新的挑战。
我使用这个通用函数从列表中选择一个随机元素
public static T PickRandom<T>(this IList<T> list) {
Random random = new Random();
int rnd = random.Next(list.Count);
return list[rnd];
}
但我想保护自己不要在0值列表中使用它。显然我不能从T以外的函数返回任何东西,例如false或-1。我当然可以这样做
if(myList.Count > 0)
foo = Utilites.PickRandom(myList);
然而,在C#中有很多疯狂的东西,我不知道,对于这个应用程序,我正在创建我非常,经常必须从列表中选择一个可以在其Count中不断递减的随机元素。还有更好的方法吗?
答案 0 :(得分:8)
您拥有的选项是
return default(T)
这将是一个模棱两可的行为,因为它可能是列表的有效元素。
或者您可以按照自己的说法返回-1
之类的内容,但这与您的代码完全相关。
或者您可以返回null
,但这只能在T
是可以为空的类型时才能完成。
在之前的所有情况下,如果来电者不知道这种情况,应用程序可能会继续使用无效值,从而导致未知后果。
所以最好的选择可能是抛出异常:
throw new InvalidOperationException();
通过这种方法,您快速失败,并确保在调用者的意图之外不会发生任何意外情况。
备份此选项的一个原因。以Linq的扩展方法为例。如果您在空列表中拨打First()
,Single()
或Last()
,则会收到InvalidOperationException
消息&#34;序列中不包含任何元素&#34 ; 。为您的班级提供类似于框架类的行为&#39;总是一件好事。
由于阿列克谢·列文科夫在问题中的评论,我添加了旁注。随机生成并不是最好的方法。看看this question。
第二方注释。您将函数声明为IList<T>
的扩展方法(通过在第一个参数之前使用this
来执行此操作)但是您将其称为静态辅助方法。扩展方法是一种语法糖,而不是这样做:
foo = Utilites.PickRandom(myList);
允许您这样做:
foo = myList.PickRandom();
有关扩展程序的更多信息,请访问here。
答案 1 :(得分:0)
另一种选择是以下一对重载而不是原始重载。有了这些,调用者应该清楚,如果无法从列表中“挑选”,他们将提供默认随机值。
public static T PickRandomOrReturnDefault<T>(this IList<T> list, T defaultRandomValue)
{
if (list == null || list.Count == 0) return defaultRandomValue;
Random random = new Random();
int rnd = random.Next(list.Count);
return list[rnd];
}
public static T PickRandomOrReturnDefault<T>(this IList<T> list, Func<T> createRandomValue)
{
if (list == null || list.Count == 0) return createRandomValue();
Random random = new Random();
int rnd = random.Next(list.Count);
return list[rnd];
}
注意:您应该考虑随机创建类的静态成员字段,而不是反复重新实例化它。请参阅此帖Correct method of a "static" Random.Next in C#?
的答案答案 2 :(得分:0)
您拥有的另一个选择是使用<?= GridView::widget([
'dataProvider' => $dataProvider,
'columns' => [
['class' => 'yii\grid\SerialColumn'],
'home_team',
'away_team',
'line',
'over_under',
'home_fd',
],
]); ?>
monad。它与Maybe<T>
非常相似,但与参考类型一起使用。
Nullable<T>
您的代码可能如下所示:
public class Maybe<T>
{
public readonly static Maybe<T> Nothing = new Maybe<T>();
public T Value { get; private set; }
public bool HasValue { get; private set; }
public Maybe()
{
HasValue = false;
}
public Maybe(T value)
{
Value = value;
HasValue = true;
}
public static implicit operator Maybe<T>(T v)
{
return v.ToMaybe();
}
}
您可以使用它:
private static Random random = new Random();
public static Maybe<T> PickRandom<T>(this IList<T> list)
{
var result = Maybe<T>.Nothing;
if (list.Any())
{
result = list[random.Next(list.Count)].ToMaybe();
}
return result;
}
就个人而言,我最后用Maybe命名我的方法。
更像是这样:
var item = list.PickRandom();
if (item.HasValue) { ... }