2

この質問のアクティブなパターンは、VS 2012 RTM にアップグレードした後、コンパイルに失敗します。型テストを実行し、単一のパターン内でリテラルを照合する方法を提供します。例えば:

let (|Value|_|) value = 
  match box value with
  | :? 'T as x -> Some x
  | _ -> None

let getValue (name: string) (r: IDataReader) =
  match r.[name] with
  | null | :? DBNull | Value "" -> Unchecked.defaultof<_>
  | v -> unbox v

これはアクティブなパターンなしで実行できますか? whenガードを使用できることはわかっていますが ( ) :? string as s when s = ""、他のパターンと組み合わせることはできません。

4

2 に答える 2

1

パラメータ化されたアクティブ パターンを使用できるはずです。

let (|Value|_|) v x = 
    if unbox x = v then 
        Some() 
    else None

使用法は、現在のものとまったく同じように見えるはずです。

編集

互換性を破る変更が意図的なものかどうかはわかりませんが、入力型とは関係のない一般的な戻り値の型を持つアクティブ パターンは、通常は避けるべきだと思います。型推論と組み合わせると、微妙なエラーを簡単に隠すことができます。(|Value|_|)元のパターンを使用して、次の例を検討してください。

match [1] with
| Value [_] -> "Singleton"
| _ -> "Huh?"

これは、実際に試みようとするものではないようです。名前はValue、リテラルでのみ使用する必要があることを意味します。パラメータ化されたアクティブ パターンは、まさにこのシナリオを可能にします。

于 2012-08-16T15:22:34.130 に答える
1

kvb のバリエーション (型テストが成功することを前提としているため、まったく同じことを行うわけではありません) を変更して、同様のパターンを生成できます。

let (|Value|_|) x value =
  match box value with
  | :? 'T as y when x = y -> Some()
  | _ -> None

ただし、微妙なパフォーマンスの違いがあります。元のアクティブなパターンは次のように変換されます。

public static FSharpOption<T> |Value|_|<a, T>(a value)
{
    object obj = value;
    if (!LanguagePrimitives.IntrinsicFunctions.TypeTestGeneric<T>(obj))
    {
        return null;
    }
    return FSharpOption<T>.Some((T)((object)obj));
}

つまり、型テストとキャストを行います。使用法 ( match x with Value "" -> ...) は次のように変換されます。

FSharpOption<string> fSharpOption = MyModule.|Value|_|<object, string>(obj);
if (fSharpOption != null && string.Equals(fSharpOption.Value, ""))
{
    ...
}

最も注目すべきは、パターンから返される型指定された値が、パターン (string.Equals文字列) の典型的なコンパイラ変換を使用して照合されることです。

更新されたパターンは次のように変換されます。

public static FSharpOption<Unit> |Value|_|<T, a>(T x, a value)
{
    object obj = value;
    if (LanguagePrimitives.IntrinsicFunctions.TypeTestGeneric<T>(obj))
    {
        T y = (T)((object)obj);
        T y3 = y;
        if (LanguagePrimitives.HashCompare.GenericEqualityIntrinsic<T>(x, y3))
        {
            T y2 = (T)((object)obj);
            return FSharpOption<Unit>.Some(null);
        }
    }
    return null;
}

これは一般的な等価性を使用し、リテラルに対するマッチングよりも効率が悪いです。等価性がパターンに組み込まれているため、使用法は少し単純です。

FSharpOption<Unit> fSharpOption = MyModule.|Value|_|<string, object>("", obj);
if (fSharpOption != null)
{
    ...
}

とにかく、それは動作します。でもオリジナルの方が好きです。

于 2012-08-16T15:45:46.620 に答える