簡體   English   中英

基礎通用接口的擴展方法

[英]Extension methods on base generic interfaces

我正在實現一個流暢的構建器模式,它需要在靜態擴展方法中接受可枚舉並迭代其內容,同時將一個仿函數應用於可枚舉的內容。 如(不是實際代碼,只是一個例子):

public static IValidator<IEnumerable<T>> Each<T>(
    this IValidator<IEnumerable<T>> enumerable, 
    Func<T, bool> action)
{
    foreach (T value in enumerable)
        action(value);

    return validator;
}

這對於枚舉非常有效,但對於繼承的類型/接口則失敗。 讓我們說:

IValidator<IEnumerable<Guid>> validator = ...;

IEnumerable<Guid> guids = ...;
validator.Each(guids, guid => guid != Guid.Empty);   // ok

IList<Guid> guids = ...;
validator.Each(guids, guid => guid != Guid.Empty);   // doesn't compile (see below)

例外是:

IValidator<IList<Guid>>不包含'Each'的定義,也沒有擴展方法'each'接受IValidator<IList<Guid>>類型的第一個參數(你是否缺少using指令或匯編引用) ?

我的問題是關於IValidator<T>的繼承鏈,更具體地說,是它的泛型類型參數T 為什么類型IValidator<IEnumerable<T>>不能從IValidator<IList<T>>分配? 我無法想到哪個IList<T>不是IEnumerable<T> (給定相同的T )。

將泛型參數約束到T : IEnumerable<R>確實有效,但是如果可能的話,這需要兩個我想避免的類型參數( TR )。

有什么想法嗎? 好的解決方案 謝謝。

這是由於IValidator<T>接口的定義。 我敢打賭它是這樣的:

public interface IValidator<T>

你真正想要的是:

public interface IValidator<out T>

這將使您的接口協變 ,這意味着您可以將IValidator<T2>的實現分配給IValidator<T> ,假設T2來自T

在這種情況下, IList<T>派生自IEnumerable<T> ,因此您應該能夠將T聲明為協變。 但是,這取決於IValidator<T>上的方法以及它們是如何暴露的。

即,如果你有方法IValidator<T>稱取的實例T在作為參數的接口上的任何方法,那么你將無法申報接口作為協變。

如果是這種情況,那么你應該能夠擺脫Each定義:

public static IValidator<T> Each<T, TValue>(
    this IValidator<T> enumerable, 
    Func<TValue, bool> action) where T : IEnumerable<TValue>
{
    foreach (TValue value in enumerable)
        action(value);

    return validator;
}

這將表明T應該來自IEnumerable<TValue>

兩個答案:

  1. where T: IEnumerable<T>哪個可以解決你的問題並且不需要第二個泛型類型是完全合法的。

  2. IValidator<IEnumerable<T>>不能從IValidator<IList<T>>分配,因為您的界面不是變體。 從v4開始,C#支持接口差異,但您必須在接口定義中明確要求它。 為此,請參閱“ out Generic Modifier

協方差允許您將更多派生類型替換為在執行賦值時期望較少派生類型的泛型參數等。

請注意,您可以確保您的界面確實是變體安全的。 這就是為什么在C#4之前不可能的原因,因為它並不總是正確的; 一些接口是安全協變的,一些是安全逆變的(你只能用較少的派生類型替換預期的類型)。 這一切都取決於你在做什么。

暫無
暫無

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

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