簡體   English   中英

如何指定顯示“可空類型的集合”的約束?

[英]How do I specify a constraint that says “collection of nullable types”?

我正在嘗試創建一個通用的參數驗證方法,該方法檢查集合參數是否為null,empty或包含null元素

public void Foo(ICollection<MyType> bar)
{
    // Validate parameters
    ThrowIfNullEmptyOrContainsNull(bar, "bar");
                  .
                  .
                  .

如果我僅在類型約束中指定ICollection<T> ,則if (value.Contains(null))生成錯誤,因為T可能不是可為空的類型。

這是我想出的,但似乎並不正確:

internal static T1 ThrowIfNullEmptyOrContainsNull<T1, T2>(T1 value, string name)
    where T1 : ICollection<T2>
    where T2 : class
{
    if (ReferenceEquals(value, null))
        throw new ArgumentNullException(name);

    if (value.Count == 0)
        throw new ArgumentException("Empty collection not allowed", name);

    if (value.Contains(null))
        throw new ArgumentException("Collection contains one or more null elements", name);

    return value;
}

...但是然后我必須使用顯式參數類型調用該方法,如下所示:

public void Foo(ICollection<MyType> bar)
{
    // Validate parameters
    ThrowIfNullEmptyOrContainsNull<(ICollection<MyType>, MyType>(bar, "bar");
                  .
                  .
                  .

如果沒有在調用中明確指定T1和T2,則會出現錯誤“無法從用法中推斷出類型實參...”。

誰能闡明該怎么做?

只是不要使用Contains 遍歷集合並將值顯式比較為null

internal static T1 ThrowIfNullEmptyOrContainsNull<T1, T2>(T1 value, string name)
    where T1 : ICollection<T2>
{
    if (ReferenceEquals(value, null))
        throw new ArgumentNullException(name);

    if (value.Count == 0)
        throw new ArgumentException("Empty collection not allowed", name);

    foreach (var item in value)
        if (item == null)
            throw new ArgumentException("Collection contains one or more null elements", name);

    return value;
}

怎么樣呢?

if (value.Any(item => item == null))
{
    throw new ArgumentException("Collection contains one or more null elements", name);
}

如:

internal static T1 ThrowIfNullEmptyOrContainsNull<T1, T2>(T1 value, string name)
    where T1 : ICollection<T2>
{
    if (ReferenceEquals(value, null)) 
        throw new ArgumentNullException(name);

    if (value.Count == 0) 
        throw new ArgumentException("Empty collection not allowed", name);

    if (value.Any(item => item == null)) 
        throw new ArgumentException("Collection contains 1 or more null items", name);

    return value;
}

擴展方法呢? 根據需要包裝異常或消息

  public static bool IsNullOrEmpty<T>(this ICollection<T> alist) where T:class
    {
        if (alist == null || alist.Count == 0){
            return true;
        }
        if (alist.Any(t => t == null)) {
            return true;
        }
        return false;
    }

采用:

 if ( myList.IsNullOrEmpty  ) {
   //.. exception, error handling
  }

無需傳遞MyList的類型,因為MyList必須實現ICollection可能對您有用,無需傳遞類型要求。
在建議中添加了T:Class。 但是您已經知道了:-)

我們可以將非空類型與null進行比較,因為所有對象都可以轉換為object ,因此可以進行比較:

bool obviouslyFalse = 1 == null;

這將導致警告,但有效。 顯然,它總是false ,實際上編譯器將通過刪除比較並給我們等效項來進行優化,就好像我們有bool obviouslyFalse = false;

對於泛型,適用於以下情況:

T item = getTFromSomewhere;
bool obviouslyFalseIfTIsntNullable = item == null;

然后,這對於所有可能的T有效,並且盡管編譯器無法刪除比較,但抖動確實可以並且確實可以。

因此,我們可以擁有:

internal static TCol ThrowIfNullEmptyOrContainsNull<TCol, TEl>(TCol collection, string name)
    where TCol : ICollection<TEl>
{
  if (ReferenceEquals(value, null))
      throw new ArgumentNullException(name);
  if (value.Count == 0)
    throw new ArgumentException("Empty collection not allowed", name);
  foreach(var item in collection)
    if(item == null)
      throw new ArgumentException("Collection cannot contain null elements", name);
  return value;
}

這會起作用,但是如果我們有大量非空類型的集合,那將會很浪費。 即使不執行任何操作,抖動也不可能刪除該迭代,因此它仍將獲得一個枚舉數並對其調用MoveNext() ,直到返回false。 我們可以幫助您:

internal static TCol ThrowIfNullEmptyOrContainsNull<TCol, TEl>(TCol collection, string name)
    where TCol : ICollection<TEl>
{
  if (ReferenceEquals(value, null))
      throw new ArgumentNullException(name);
  if (value.Count == 0)
    throw new ArgumentException("Empty collection not allowed", name);
  if(default(TEl) == null)
    foreach(var item in collection)
      if(item == null)
        throw new ArgumentException("Collection cannot contain null elements", name);
  return value;
}

因為default(TEl) == null對於可為null的類型(包括Nullable<T> )始終為true,對於非可為null的類型始終為false,因此通過消除所有類型的比較並為非null的類型刪除整個枚舉,將優化抖動-可空類型。 因此,該方法將可以立即處理大量的整數數組(例如)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM