8

イントロ

この質問は、新しい言語機能の提案をこのサイトに投稿して、それらに関する一般的な意見を収集するというMarcGravellの提案によって促されました。

アイデアは、彼らが役立つかもしれないか、あるいは私が求めていることを達成するための別の方法がすでにあるかどうかを集めることです。

提案(制約付きタイプ)

VB.Netの通常の変数宣言は、次のように記述されます。

Dim SomeVariable as SomeType

次のフォームを許可することをお勧めします

Dim SomeVariable1 as {SomeType, ISomeInterface}
Dim SomeVariable2 as {SomeType, ISomeInterface, ISomeOtherInterface}

この構文は、ジェネリックスを制約するVb.Netのスタイルから借用しています。

なぜこれを許可するのですか?...それは何のために良いですか?

私が最初に考えた特定のケースは、コントロールの特定のサブセットを定義することでした。いくつかのビジネスルールに基づいてコントロールを提供する一連のコントロールファクトリのインターフェイスを作成したいと思いました。

これらのコントロールの利用者は、インターフェイスを介して、作成されたすべてのコントロールが、通常のコントロールには通常見られない追加機能をすべてのコントロールに提供する一連のインターフェイス(私の場合は1つのみ)も実装する必要があります。

以下は現在機能しないことに注意してください。

Public Interface ISpecialControl
End Interface

Public Interface IControlProvider
    Function CreateControl(Of T As {Control, ISpecialControl})() As T
End Interface

Public Class SpecialTextBoxProvider
    Implements IControlProvider
    Public Function CreateControl(Of T As {Control, ISpecialControl})() As T Implements IControlProvider.CreateControl
        Return New SpecialTextBox
    End Function
End Class

Public Class SpecialTextBox
    Inherits TextBox
    Implements ISpecialControl
    Public Sub New()

    End Sub
End Class

これはC#に次のように変換されると思います。

public interface ISpecialControl
{
}

public interface IControlProvider
{
    T CreateControl<T>()
        where T : Control, ISpecialControl;
}

public class SpecialTextBoxProvider : IControlProvider
{
    public T CreateControl<T>()
        where T : Control, ISpecialControl
    {
        return new SpecialTextBox();
    }
}

public class SpecialTextBox : TextBox, ISpecialControl
{
}

SpecialTextboxをTにキャストできないため、「NewSpecialTextbox」を返そうとして失敗します。

"Value of type 'MyApp.SpecialTextBox' cannot be converted to 'T'"

私の工場は単純なコントロールを返すことができ、実行時にISpecialControlが実装されているかどうかを確認できますが、これにより実行時の問題が発生し、現在は実用的ではない場合でも論理的な可能性があるため、コンパイル時に確認したいと思います。

更新:これらのファクトリは外部(おそらくサードパーティ)のアセンブリに配置され、必要なコントロールライブラリに依存して、ISpecialControlも実装したこれらのコントロールの派生物を作成して返すことができるという考え方です。

これらのアセンブリは、自己構成リフレクション(最初のパスでのリフレクションとそれに続く構成で使用され、その後の実行で使用されます)を介して配置され、これらのコントロールがどのような依存関係を持っているかについて、呼び出し側アセンブリが知らないうちに使用できます。

これらのファクトリは、ポイントを無効にするため、呼び出すことが期待されるコントロールに関する情報を渡さずに構築可能である必要があります。

それで、あなたはどう思いますか...これは役に立ちますか?...これを達成するためのより良い方法はありますか?これを達成する方法はすでにありますか?

4

7 に答える 7

1

表面的には便利ですが、この種のことは次の 2 つのいずれかで処理する方が適切だと思います。

  • 動的 (VS2010 で導入) を介したダック タイピングにより、型の安全性は削除されますが、柔軟性が大幅に向上します。
  • 一般的な構成

元の例はどちらも必要とせず、次のように簡単に機能させることができます。

public interface IControlProvider<T>
    where T : Control, ISpecialControl
{
    T CreateControl();
}

public class SpecialTextBoxProvider : IControlProvider<SpecialTextBox>
{
    public SpecialTextBox CreateControl()
    {
        return new SpecialTextBox();
    }
}

実際、ほとんどのコントロールにはデフォルトの public コンストラクターがあるため、さらに簡単にすることができます。

public class ControlProvider : IControlProvider<T>
    where T : Control, ISpecialControl, new()
{
    public T CreateControl()
    {
        return new T();
    }
}

var control = ControlProvider<SpecialTextBox>.CreateControl();

SpecialTextBox への参照依存関係を直接取得しないコードの呼び出しに関する追加の制限を考えると、これは機能しません。

于 2009-02-16T22:32:40.260 に答える
0

それは便利な言語機能のように思われるでしょう。複数の制約に準拠している以外に型が不明なメソッドパラメータを持つことは可能ですが、そのような関数に渡したり、型キャストしたりできるような方法でそのようなパラメータをフィールドに格納する方法はありません。合格した。

ただし、少し不格好ですが、目的の基本的な結果を達成する別の方法があります。私の質問を参照してください。複数のインターフェイスを実装し、特定のベース(.net)から派生したオブジェクトを保存すると、私が作成できた最良のアプローチが提供されます。

于 2010-12-13T23:45:16.307 に答える
0

編集:ああ、私が正しく読んでいないのを待ってください、これはそれを2つのタイプに制限することであり、2つのタイプの選択ではありません。でも、下記のクラスと同じように解決できると思います...

この動作をシミュレートするために、クラスを1回試しました。

public class Choice<T1, T2> 
{
    private readonly T1 value1;
    private readonly T2 value2;

    public Choice(T1 value)
    {
        value1 = value;
    }

    public Choice(T2 value) 
    {
        value2 = value;
    }

    public static implicit operator T1(Choice<T1, T2> choice) 
    {
        return choice.value1;   
    }

    public static implicit operator T2(Choice<T1, T2> choice) 
    {
        return choice.value2;   
    }

    public static implicit operator Choice<T1, T2>(T1 choice) 
    {
        return new Choice<T1, T2>(choice);
    }

    public static implicit operator Choice<T1, T2>(T2 choice) 
    {
        return new Choice<T1, T2>(choice);
    }

    public T1 Value1
    {
        get { return value1; }
    }

    public T2 Value2
    {
        get { return value2; }
    }
}

これにより、次のような構成を作成できます。

[TestMethod]
public void TestChoice() 
{
    TestChoice("Hello");
    TestChoice(new []{"Hello","World"});
}

private static void TestChoice(Choice<string[], string> choice)
{
    string value = choice;
    string[] values = choice;

    if (value != null)
        Console.WriteLine("Single value passed in: " + value);

    if (values != null) {
        Console.WriteLine("Multiple values passed in ");
        foreach (string s in values)
            Console.WriteLine(s + ",");
    }
}

暗黙的な演算子の欠点は、インターフェイスへの暗黙的なキャストを行わないことです(インターフェイスタイプからのキャストは機能します)。そのため、含まれている値をからにキャストしようとすると、の代わりに渡すことは機能しませIEnumerable<T>ん。string[]Choice<IEnumerable<T>, T>IEnumerable<T>

一般的に私はオーバーロード/インターフェースを使用することを好むので、ここで誤解しないでください:)

プロパティを使用する場合(およびその理由でオーバーロードを使用できない場合)、たとえば許可list<string>するだけのDataSourceプロパティのような場合に便利です。list<ListItem>

于 2009-05-20T15:29:40.457 に答える
0

これは拡張メソッドとは実質的に異なりますか?コントロールを拡張してみませんか?

于 2009-05-19T04:28:10.443 に答える
0

「制約された型」よりも「制約された変数」ですが、間違いなく興味深いものです。一般的な制約と同様に、競合するメンバーが存在する場合、おそらくいくつかの小さな問題が解決されますが、一般的な制約と同じ回避策がおそらく適用されます。

もちろん、実用的な見方では、すでにキャストなどを行うことができますが、その後、2 つの参照を互いに最新の状態に保つ必要があります...

うーん...面白い。

于 2009-02-16T11:51:56.383 に答える
0

インターフェイス構成を使用するのはどうですか?

あなたが持っている

interface IA;
class B;

存在する場合は、クラス B のインターフェイスを使用してコンポジットを作成します

interface IB;
interface IAB : IA, IB;

クラスを変更する

class C : B, IA

複合インターフェースを実装する(問題は発生しないはずです)

class C : B, IAB

また、インターフェイス IAB を制約タイプとして使用できます。

于 2009-02-16T12:43:00.643 に答える
0

あなたが何を提案しているのか理解できません。それは私の問題だと思います。

ただし、特定のインターフェイスを実装するコントロールを返したいので、私には聞こえます。

メソッドがその特定のインターフェイスを返すとだけ言うことができないのはなぜですか? 「Control から派生し、インターフェイス ISomeInterface も実装するクラスを返したい」と言っているように思えます。

おそらく解決策は、必要な Control の部分を独自のインターフェイスに抽出し、両方を実装するオブジェクトを返すように指定することでしょうか?

このような:

interface IControl { ... }
interface ISomeInterface { ... }

interface IControlInterface : IControl, ISomeInterface { ... }

この最後のインターフェイスは、両方の基本インターフェイスを実装するオブジェクトが必要であることを指定します。これは、要件の 1 つをインターフェイスではなく基本クラスにすることを除いて、あなたが望むように聞こえます。

インターフェースを使うだけでこれを解決できると思います。

于 2009-02-16T12:51:52.870 に答える