質問

次のインターフェイスがあるとします。

interface IEntity
{
    int Id{get;}
} 

interface IPerson : IEntity
{
    string Name{get;} 
    int Age{get;}
}

interface ITeacher : IPerson 
{
    string StaffId{get;}
}

interface IStudent : IPerson 
{
    string StudentId{get;}
    string Courses{get;}
}

interface IRepository
{
    T Get<T>(int id) where T : IEntity
}

私の名前空間には次のクラスがあります

public class EntityBase() : IEntity
{
    int Id{get;set;}
}
public class Teacher : EntityBase, ITeacher{}
public class Sudent : EntityBase, IStudent{}

現在、この IRepository を次のように実装しています。

class Repository: IRepository
{
    IDataContext Context{get;set;}

    T Get<T>(int id) where T : EntityBase
    {
        if(typeof(T) == typeof(Teacher))
            return Context.Get<ITeacher>(id);
        if(typeof(T) == typeof(Sudent))
            return Context.Get<ISudent>(id);
        throw new Exception("Unknown Interface " + typeof(T).Name);
    }
}

これを実装するより良い方法はありますか?Context はデータ型 (Teacher、Student) については何も知らず、そのインターフェイス (ITeacher、IStudent) だけを知っているとします。

このようなことができるでしょうか?

class Repository: IRepository
{
    T Get<T>(int id) where T : EntityBase
    {
        var MyInterface = FindInterface<T>();
        return Context.Get<MyInterface>(id);
    }
}
役に立ちましたか?

解決

これでできると思います:

class Repository: IRepository
{
    IDataContext Context{get;set;}

    T Get<T>(int id) where T : EntityBase    
    {
        string[] interfaceList = new string[] 
            { "ITeacher", "IStudent"};

        Type interfaceType = null;
        foreach (string s in interfaceList)
        {
            var types = typeof(T).FindInterfaces((x, y) => x.Name == y.ToString(), s);

            if (types.Length > 0)
                interfaceType = types[0];
        }

        if (interfaceType == null)
            throw new Exception("Unknown Interface " + typeof(T).Name);

        MethodInfo method = typeof(Context).GetMethod("Get");
        MethodInfo generic = method.MakeGenericMethod(interfaceType);

        var returnValue = generic.Invoke(Context, new object[] { id });

        return (T)Convert.ChangeType(returnValue, typeof(T));
    }
}

編集: 名前空間の名前がわからないため、Name プロパティを使用してインターフェイスをフィルター処理しました。実際の使用法では、念のため次のように FullName を使用することをお勧めします。

...
string[] interfaceList = new string[] 
                { "MyNamespace.ITeacher", "MyNamespace.IStudent"};
...
var types = typeof(T).FindInterfaces((x, y) => x.FullName == y.ToString(), s);

他のヒント

私はあなたがContextクラスのGetメソッドを見つけて、私はこれをテストしていない、呼び出し側が提供する型Tのための一般的な呼び出しとして、それを呼び出すことにより、反射によってこれを実現することができると思いますが、コードは次のようになります:

T Get<T>(int id) where T : EntityBase
{
    Type context = Context.GetType();

    MethodInfo getMethod = context.GetMethod("Get", BindingFlags.Public);
    MethodInfo genericGet = getMethod.MakeGenericMethod(new [] {typeof(T)});

    return (T)genericGet.Invoke(Context, new object[] { id } );
}

逆の意味で言っているように私には見えます。インターフェースタイプを渡したくありません Context.Get<>, 、 あなたは?

// is this what you mean?
if (typeof(T) == typeof(ITeacher))
    return Context.Get<Teacher>(id);

そうであれば、使用する必要があります MakeGenericMethod, 、 見る これ 例として挙げます (キャッシュ部分に注目してください)。
そうでない場合は、LINQ やリポジトリ パターンの概念を誤解している可能性があります。

しかし、なぜインターフェイスを使用することにしたのか興味があります。いずれにせよ、LINQ オブジェクトは POCO ですが、リフレクション経由で DataContext のジェネリック メソッドを呼び出す (grrsh!) ことを伴う抽象化レイヤーをなぜ追加するのでしょうか?

シンプルな return Context.Get<T>(id) 次のように実現できます。

class Repository : IRepository
{
   public IDataContext Context { get; set; }



   public T Get<T>(int id) where T : IEntity, new()
  {



      return Context.Get<T>(id);



  }
}

以下は、コンテキストの実装を含むオブジェクト/インターフェイス モデルです。

 interface IEntity
{
    int Id{get;}
} 

interface IPerson : IEntity
{

}

interface ITeacher : IPerson 
{

}

interface IStudent : IPerson 
{

}

interface IDataContext
{
    T Get<T>(int id) where T:new();

}

interface IRepository  
{
    T Get<T>(int id) where T : IEntity , new() ;
}


public class EntityBase : IEntity
{
   public virtual int Id{get;set;}
}


public class Teacher : EntityBase, ITeacher {

    int id=0;
    public override int Id { 

                    get { return this.id; }

                    set { this.id = value; } 


                 }

}
public class Student : EntityBase, IStudent 
{
    int id=0;
    public override int Id {

                    get { return this.id; }

                    set { this.id = value; } 
                  }

}




class Context<T>: IDataContext where T: EntityBase,  new() 
{
    ArrayList store;


    public Context(int dataSize) 
    {
         store = new ArrayList(dataSize);

        for (int i = 0; i < dataSize; i++)
        {

            T t = new T();
            t.Id = i;           
            store.Add(t);


        }

    }    

    public T Get<T>(int i) where T:new()
    {
        if (i<store.Count)
        {   

            return (T)store[i]; 
        }

        else
        {
            return default(T);
        }

    }


}

最後に、メイン メソッド クラスで、すべてが適切に連携していることを示します。

 using System;
 using System.Collections;

class MyClass
{

    static void Main(string[] args)
    {



        Context<Teacher> teachersContext  = new Context<Teacher>(100);//contructs a db of 100 teachers
        Context<Student> studentsContext = new Context<Student>(100);//contructs a db of 100 teachers 

        Repository repo = new Repository();




        // set the repository context and get a teacher

        repo.Context = teachersContext;
        Teacher teacher1 = repo.Get<Teacher>(83); //get teacher number 83
        Console.WriteLine("Teacher Id:{0} ", teacher1.Id);



        // redirect the repositry context and now get a student

        repo.Context = studentsContext;
        Student student1 = repo.Get<Student>(35); //get student  number 35

        Console.WriteLine("Student Id: {0} ", student1.Id);



        Console.ReadLine();

    }
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top