4

私は一般的な方法を持っています:

public bool DoSomething<T>(T item) where T: IBase
{
    return DoSomethingSpecific(item);
}

public bool DoSomethingSpecific(IBase item)
{
    return true;
}

public bool DoSomethingSpecific(IAdvanced item)
{
    return false;
}

IAdvanced インターフェイスは、IBase インターフェイスから派生/継承することに注意してください。

IAdvanced 型の項目で DoSomething を呼び出すと、常に false が返されることがわかりました。私はこれを理解していません。IAdvanced は IBase 型であるため (このインターフェイスの子であるため)、DoSomethingSpecific メソッドの 2 つのオーバーロードされた型の間で混乱が生じる可能性があることはわかっています。ただし、C# の知識が限られているため、ここでは IAdvanced メソッドを選択する必要があります。これは、私がこの結論を下した方法の例です。

public class Advanced: IAdvanced
{

   public void CallMethod()
   {
      DoSomething(this);
   }
}

これにより、真の値が得られます。

しかし、もしそうなら:

public class Advanced: IAdvanced
{

    public void CallMethod()
    {
       DoSomethingSpecific(this);
    }
}

それは false を返します。これは私が期待するものです。

私はこれまでジェネリックを使用したことがないと言わざるを得ません。私は試みましたが、常にこのようなケースに行き詰まり、ジェネリックを使用するポイントを完全に理解できません(ツリーやリンクリストなどのデータ構造以外)。

今回はアドバイスを頂きたくてここに来ました。私がやろうとしていることに明確な問題はありますか? 私がここで忙しくしていることをやろうとするのは、おそらく意味がないのでしょうか?

4

3 に答える 3

4

これを再現できません。つまり、何か他のことが起こっている可能性があります。常にtrueを返すと言うつもりだったのではないかと思います。それが私がここに見るものです:

using System;

public interface IBase {}
public interface IAdvanced : IBase {}

public class Base : IBase {}
public class Advanced : IAdvanced {}

class Test
{
    public static bool DoSomething<T>(T item) where T: IBase
    {
        return DoSomethingSpecific(item);
    }

    public static bool DoSomethingSpecific(IBase item)
    {
        return true;
    }

    public static bool DoSomethingSpecific(IAdvanced item)
    {
        return false;
    }

    static void Main()
    {
        Console.WriteLine(DoSomething(new Base()));     // True
        Console.WriteLine(DoSomething(new Advanced())); // True
    }    
}

また、次のように記述します。

IAdvanced は IBase 型であるため (このインターフェイスの子であるため)、DoSomethingSpecific メソッドの 2 つのオーバーロードされた型の間で混乱が生じる可能性があることはわかっています。ただし、C# の知識が限られているため、ここでは IAdvanced メソッドを選択する必要があります。

確かに、あなたは返されることを期待 falseすべきですが、私は返されることを期待trueしています.

ご覧のとおりDoSomething<T>、そのメソッドがコンパイルされると、内部のオーバーロードの解決が決定されます。その選択は1 度だけ行われますT。そのため、コンパイル済みの の IL を見ると、neverへの呼び出しのみDoSomething<T>が表示されます。ここにはポリモーフィズムはありません。DoSomethingSpecific(IBase) DoSomethingSpecific(IAdvanced)

これを「修正」する方法については、本当に達成したいことをより詳細に説明する必要があります。具体的には、次のコードがあればどうしたいですか:

IBase x = new AdvancedImplementation();
DoSomething(x);

ここでTは になりますIBaseが、は の実装を参照しIAdvancedます。この場合に実行したいDoSomethingSpecific(IAdvanced)場合、および C# 4 を使用している場合は、動的型付けを使用できます。

public static bool DoSomething(IBase item)
{
    dynamic dynamicItem = item;
    // Dispatch dynamically based on execution-time type
    return DoSomethingSpecific(dynamicItem);
}

メソッドがもはやジェネリックである必要がないことに注意してください - それは何のメリットもありません。

一方、 のみに基づいてどちらを呼び出すかを決定しTたい場合は、ivowiblo のソリューションのようなものを使用する必要があります。

個人的には、これらの解決策の両方を回避しようとします。通常、この種のことは、他の方法で改善できる設計の兆候であることがわかります。

于 2012-05-27T20:27:44.953 に答える
2

コンパイル時のチェックを削除して、ランタイムにします。

public bool DoSomething(IBase item)
{
    var itemAdvanced = item as IAdvanced;
    if (itemAdvanced != null)
        return DoSomethingSpecific(itemAdvanced);
    else
        return DoSomethingSpecific(item);
}

その理由は、呼び出し元がオブジェクトを静的に知っているだけIBaseで、実行時にそれがである場合、それを?IAdvancedとして扱うことが好ましいのではないかということです。IAdvancedこれはおそらくあなたがやりたいことをするための最速の方法でもあります。dynamicたとえば、さまざまな方法が多数存在する可能性があるため、必要があると思われる場合にのみ、このアプローチを採用します。

于 2012-05-28T00:18:11.067 に答える
1

それが知る限り、それはIBaseです。コンパイラは、どのメソッドを呼び出しているかを判断する必要があります。そのため、コンパイラは常にそのメソッドを選択します。

汚いトリックはこれを行うことです:

public static bool DoSomething<T>(T item) where T: IBase
{
    var isAdvanced = typeof(IAdvanced).IsAssignableFrom(typeof(T));
    return isAdvanced ? DoSomethingSpecific((IAdvanced)item) : DoSomethingSpecific(item);
}

もう1つの方法は、Double-Dispatch/Visitorパターンを使用することです。

public interface IDoSomethingVisitor {
    bool DoSomethingSpecific(IBase base);
    bool DoSomethingSpecific(IAdvanced adv);
}

DoSomethingメソッドはIBaseインターフェイスにあります。

public interface IBase{
    void DoSomething(IDoSomethingVisitor visitor);
}

そしてあなたの実装では:

public class Base : IBase
{
   public bool DoSomething(IDoSomethingVisitor visitor)
   {
      visitor.DoSomething(this);
   }
}

public class Advanced : IAdvanced
{
   public bool DoSomething(IDoSomethingVisitor visitor)
   {
      visitor.DoSomething(this);
   }
}

この場合、問題は純粋な継承を使用して解決されます。実際のインスタンスは、呼び出すメソッドを解決するインスタンスです。ifsはありません。

于 2012-05-27T20:31:42.890 に答える