Domanda

    

Questa domanda ha già una risposta qui:

         

Date le seguenti interfacce:

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
}

Ho le seguenti classi nel mio spazio dei nomi

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

Attualmente sto attuazione del presente IRepository come segue:

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);
    }
}

C'è una Betterway di applicazione del presente? Dato che il nostro contesto non è a conoscenza dei nostri tipi di dati (insegnante, studente), appena le sue interfacce (ITeacher, IStudent).

Can qualcosa di simile a questo lavoro?

class Repository: IRepository
{
    T Get<T>(int id) where T : EntityBase
    {
        var MyInterface = FindInterface<T>();
        return Context.Get<MyInterface>(id);
    }
}
È stato utile?

Soluzione

Credo che questo farà:

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));
    }
}

Modifica Come io non conosco il nome dello spazio dei nomi, ho usato la proprietà Name per filtrare le interfacce. Nell'uso mondo reale io suggerisco di utilizzare FullName solo per essere sicuri, in questo modo:

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

Altri suggerimenti

Penso che si possa raggiungere questo obiettivo attraverso la riflessione, trovando il metodo Get sulla classe del contesto, e invocando come una chiamata generica per il tipo T. fornito dal chiamante non ho ancora testato, ma il codice dovrebbe essere simile a questo :

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 } );
}

Sembra a me come vuoi dire che il contrario. Non si vuole far passare tipi di interfaccia a Context.Get<>, fare?

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

Se lo è, è necessario utilizzare MakeGenericMethod, vedere questo per un esempio (si noti la parte caching).
Se non lo è, si potrebbe essere malinteso alcuni concetti di LINQ e / o Pattern Repository.

Comunque io sono curioso di sapere perchè hai deciso di utilizzare le interfacce. oggetti LINQ sono POCO in ogni modo, perché l'aggiunta di un altro strato di astrazione che coinvolge (grrsh!) chiamare i metodi generici sul DataContext attraverso la riflessione?

Una semplice return Context.Get<T>(id) potrebbe essere realizzato come segue:

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



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



      return Context.Get<T>(id);



  }
}

Di seguito viene riportato l'oggetto / modello di interfaccia con l'attuazione per il contesto

 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);
        }

    }


}

Ora finalmente la classe principale metodo di dimostrare che tutti si blocca insieme piacevolmente.

 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();

    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top