3

私は次のクラスを持っています:

// -- model hierarchy
public interface IJob {
}

public abstract class AbstractJob : IJob {
}

public class FullTimeJob : AbstractJob {               
}

// -- dao hierarchy
public interface IJobDao<T> where T : IJob {       
  T findById(long jobId);
  long insert(T job);
}

public interface IFullTimeJobDao : IJobDao<FullTimeJob> {        
}

public abstract class AbstractDao {    
}

public abstract class AbstractJobDaoImpl<T> : AbstractDao, IJobDao<T> where T : IJob {
  public T findById(long jobId) {
    // omitted for brevity
  }

  public long insert(T job) {
    // omitted for brevity
  }
}

public class FullTimeJobDaoImpl : AbstractJobDaoImpl<FullTimeJob>, IFullTimeJobDao {
}

ファクトリ メソッドから次のコードを呼び出していますが、動作していないようです。

public IJobDao<IJob> createJobDao(long jobDaoTypeId)
{
    object jobDao = Activator.CreateInstance(typeof(FullTimeJobDaoImpl));
    return jobDao as IJobDao<IJob>; // <-- this returns null
    return (IJobDao<IJob>) jobDao; // <-- this cast fails
}

この「アップキャスト」はどのように適切に達成されますか?

4

3 に答える 3

4

インターフェイスをIJobDao共変にします。

public interface IJobDao<out T> where T : IJob
{
    T findById(long jobId);
}

アップデート:

ジェネリック値を返すことと受け取ることの両方をインターフェイス メソッドに持たせ、同時にそれを共変にすることはできません。

可能な解決策:

  • IJobDao<T>-の非ジェネリック バージョンを作成しますIJobDao(もちろん、両方のインターフェイスをクラスに実装し、 を実装する必要がありますIJobDao<T>) 。
  • IJobDao<T>2 つのインターフェースに分割(1 つは共変、もう 1 つは反変)
  • 非ジェネリック インターフェイスのみを使用したソリューションを検討してIJobDaoください (とにかく、ジェネリックの主な目的であるタイプ セーフが得られません)。

最初のシナリオの実装に関するいくつかのアイデア:

public interface IJobDao
{
    IJob findById(long jobId);

    long insert(IJob job);
}

public interface IJobDao<T> : IJobDao
    where T : IJob
{
    new T findById(long jobId);

    new long insert(T job);
}

public abstract class JobDaoBase<T> : IJobDao<T>, IJobDao
    where T : IJob
{
    public abstract T findById(long jobId);

    public abstract long insert(T job);

    IJob IJobDao.findById(long jobId)
    {
        return findById(jobId);
    }

    long IJobDao.insert(IJob job)
    {
        return insert((T)job);
    }
}

public class FullTimeJobDaoImpl : JobDaoBase<FullTimeJob>
{
    public override FullTimeJob findById(long jobId)
    {
        // implementation
    }

    public override long insert(FullTimeJob job)
    {
        // implementation
    }
}

// we are still unable to return generic interface, but we don't need to.
public static IJobDao createJobDao(/* my params */)
{
    object jobDao = Activator.CreateInstance(typeof(FullTimeJobDaoImpl));
    return jobDao as IJobDao;
}
于 2012-12-26T03:31:44.247 に答える
3

このキャストを可能にするには、インターフェイスの型パラメーターをout次のようにマークする必要があります。

public interface IJobDao<out T> where T : IJob {...}

それで

object jobDao = Activator.CreateInstance(typeof(FullTimeJobDaoImpl));
var r = jobDao as IJobDao<IJob>; //not null

しかし、これはインターフェースにいくつかの制限をもたらします。詳細については、(ジェネリック修飾子) (C# リファレンス)を参照してください。

ジェネリック インターフェイスでは、次の条件を満たす場合、型パラメーターを共変として宣言できます。

  1. 型パラメーターは、インターフェイス メソッドの戻り値の型としてのみ使用され、メソッド引数の型としては使用されません。
  2. 型パラメーターは、インターフェイス メソッドの一般的な制約として使用されません。
于 2012-12-26T03:29:34.720 に答える
0

コンテナーで制御の反転アプローチを使用することを検討してください。さまざまな実装がコンテナーに登録されます。リゾルバーは (x) のインスタンスを問い合わせます。多くの IOC コンテナー ツールの 1 つとして Unity を参照してください。

于 2012-12-26T03:54:04.307 に答える