Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/258.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 基于参数类型调用函数_C#_.net_List_Generics_Interface - Fatal编程技术网

C# 基于参数类型调用函数

C# 基于参数类型调用函数,c#,.net,list,generics,interface,C#,.net,List,Generics,Interface,我试图找出如何简化以下内容 假设我有两个实体类 public class A { public int Id { get; set; } public string Name { get; set; } public string City { get; set; } } 及 相似但不相同的类 每个类都有一个用于CRUD操作的存储库类,例如 public class RepA { public static List<A> GetAll()

我试图找出如何简化以下内容

假设我有两个实体类

public class A
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string City { get; set; }
}

相似但不相同的类

每个类都有一个用于CRUD操作的存储库类,例如

public class RepA
{
    public static List<A> GetAll()
    {
        List<A> list = new List<A>();

        A a1 = new A() {Id=1, Name="First A", City="Boston"};
        A a2 = new A() {Id=2, Name="First B", City="Chicago"};
        A a3 = new A() {Id=3, Name="First C", City="San Francisco"};

        list.Add(a1);
        list.Add(a2);
        list.Add(a3);
        return list;
    }

    public static void SaveAll(List<A> list)
    {
        foreach (A a in list)
        {
              Console.WriteLine("Saved Id = {0} Name = {1} City={2}", 
                  a.Id, a.Name, a.City);
        }
    }

}

创建
基类
或使用:

公共接口IBase
{
List GetAll();
void SaveAll(列表项);
}
公共类RepA:IBase
{
公共列表GetAll(){返回新列表();}
公共void SaveAll(列表repA){}
}
公共类代表:IBase
{
公共列表GetAll(){返回新列表();}
公共void SaveAll(列表repB){}
}
void Main()
{
IBase chosenType=随机chosenType();
var list=chosenType.GetAll();
}

您可以让存储库实现一个接口,比如说
IGetAllSaveAll
。然后,您可以将存储库存储在列表中,并将它们转换到该接口。这样,您就可以对所有这些对象调用
GetAll
函数: (实际上,第一个接口不是必需的,您可以直接将其编写为
IEnumerable GetAll()
…)

然后,您可以在某个地方保存所有这些存储库的词汇:

Dictionnary<Type, IGetAllSaveAll> myDic;
然后称之为:

Type t = RandomChosenType();
myDic[t].GetAll();

基于反射和对类结构的一些假设,尝试这种方法:

static void Main(string[] args)
{
    var types = Assembly.GetExecutingAssembly().Modules
        .SelectMany(m => m.GetTypes())
        .Where(t =>
            t.GetMethod("GetAll") != null &&
            t.GetMethod("SaveAll") != null &&
            t.GetMethod("GetAll").ReturnType.IsGenericType)
        .Select(t =>
            new
            {
                RepositoryType = t,
                ReturnTypeArgument = 
                    t.GetMethod("GetAll").ReturnType.GenericTypeArguments[0]
            }
            )
        .ToList();

    (new List<dynamic> { new A(), new B() }).ToList().ForEach(chosenType =>
    {
        var association = types
            .FirstOrDefault(t => 
                t.ReturnTypeArgument == chosenType.GetType());
        if (association == null)
            return;
        var repType = association.RepositoryType;
        dynamic list = repType.GetMethod("GetAll")
            .Invoke(chosenType, new object[] { });
        repType.GetMethod("SaveAll")
            .Invoke(chosenType, new object[] { list });
    });
}
static void Main(字符串[]args)
{
var types=Assembly.getExecutionGassembly().Modules
.SelectMany(m=>m.GetTypes())
.其中(t=>
t、 GetMethod(“GetAll”)!=null&&
t、 GetMethod(“SaveAll”)!=null&&
t、 GetMethod(“GetAll”).ReturnType.IsGenericType)
.选择(t=>
新的
{
RepositoryType=t,
ReturnTypeArgument=
t、 GetMethod(“GetAll”).ReturnType.GenericTypeArguments[0]
}
)
.ToList();
(新列表{new A(),new B()}).ToList().ForEach(chosenType=>
{
变量关联=类型
.FirstOrDefault(t=>
t、 ReturnTypeArgument==chosenType.GetType());
if(关联==null)
返回;
var repType=association.RepositoryType;
动态列表=repType.GetMethod(“GetAll”)
.Invoke(chosenType,新对象[]{});
repType.GetMethod(“SaveAll”)
.Invoke(chosenType,新对象[]{list});
});
}

您发布的代码使用静态方法。为了实现接口,您将需要实例方法。除非您想使用反射(我认为应该避免),否则这些方法需要不知道类型。大概是这样的:

public interface IRepository {
    IEnumerable<object> GetAll();
}
公共接口IRepository{
IEnumerable GetAll();
}
在RepA中:

IEnumerable<object> IRepository.GetAll() {
    return RepA.GetAll();
}
IEnumerable IRepository.GetAll(){
返回RepA.GetAll();
}

您的每个菜单选项都可以在类型为
IRepository
的字段中包含相应存储库类的实例,而不是存储类型。对其中一个实例调用
GetAll
后,如果需要,您可以稍后将结果强制转换为特定类型(如
List
)。

您应该使用一个通用存储库。这些操作应由代理处理。存储库可以如下所示:

public class GenericRepositoryExample
{

    public void Save<T>(IList<T> persons, SaveDelegate<T> save)
    {
        foreach (T person in persons)
        {
            Console.WriteLine(save(person));
        }
    }
}
为了说明此设置的使用,我创建了以下单元测试:

  [Test]
    public void TestGenericRepository()
    {
        IList<A> aList = new List<A>();

        aList.Add(new A() { Id = 1, name = "George", city = "Chicago"});
        aList.Add(new A() { Id = 2, name = "Bill", city = "Toledo" });


        List<B> bList = new List<B>(); 

        bList.Add(new B() {Id= 1, Nom = "Nathalie", ville = "Paris"});
        bList.Add(new B() {Id = 2, Nom = "Michelle", ville = "Lyon"});


        GenericRepositoryExample repository = new GenericRepositoryExample();

        repository.Save<A>(aList,HelperClass.EnglishSave);

        repository.Save<B>(bList,HelperClass.FrenchSave);

    }
[测试]
public void TestGenericRepository()
{
IList aList=新列表();
Add(新的A(){Id=1,name=“George”,city=“Chicago”});
Add(新的A(){Id=2,name=“Bill”,city=“Toledo”});
List bList=新列表();
添加(新的B(){Id=1,Nom=“Nathalie”,ville=“Paris”});
添加(新的B(){Id=2,Nom=“Michelle”,ville=“Lyon”});
GenericRepositoryExample repository=新的GenericRepositoryExample();
Save(aList,HelperClass.EnglishSave);
Save(bList,HelperClass.FrenchSave);
}

给定您的确切场景,其中您有一个代表每种可能的数据类型的枚举,下面是一些可能有效的方法

使用属性将每个枚举值映射到存储库类型。每个存储库继承自一个泛型类,该类实现一个非强类型的基本接口。repo方法从静态成员变为实例成员。基本repo类必须进行强制转换才能将
对象
转换为适当的类型并返回,但实际的存储库实现是强类型的

您可以更进一步,尝试使用表达式树缓存一些反射,这样您只需执行一次,但这取决于您真正需要优化的程度

public enum ChosenType {
    [Repo(typeof(RepA))] A = 0,
    [Repo(typeof(RepB))] B = 1
}

public class RepoAttribute : Attribute {
    public RepoAttribute(Type repoType) { RepoType = repoType; }
    public Type RepoType { get; set; }
}

class Program
{
    static void Main()
    {
        ChosenType chosentype = RandomChosenType(); //A or B

        // Make an instance of the appropriate repo based on the mapping
        // to the enum value.
        // This is a moderately expensive call, and there's room for improvement
        // by using expression trees and caching lambda expressions.
        var repo = (IRepo)Activator.CreateInstance(
            ((RepoAttribute)typeof(ChosenType).GetMember(chosentype.ToString())
                .Single().GetCustomAttributes(typeof(RepoAttribute), false).Single()
            ).RepoType);

        var list = repo.GetAll();
        repo.SaveAll(list);

        Console.Read();
    }

    static Random _rand = new Random();
    static ChosenType RandomChosenType()
    {
        return (ChosenType)_rand.Next(0, 2);
    }
}

public class A { /* No change */ }
public class B { /* No change */ }

public interface IRepo {
    List<object> GetAll();
    void SaveAll(List<object> list);
}

public abstract class Repo<T> : IRepo {
    List<object> IRepo.GetAll() {
        return GetAll().Cast<object>().ToList();
    }

    void IRepo.SaveAll(List<object> list) {
        SaveAll(list.Cast<T>().ToList());
    }

    public abstract List<T> GetAll();
    public abstract void SaveAll(List<T> list);
}

public class RepA : Repo<A> {
    public override List<A> GetAll() { /* No change except the signature */ }
    public override void SaveAll(List<A> list) { /* No change except the signature */ }
}
public class RepB : Repo<B> {
    public override List<B> GetAll() { /* No change except the signature */ }
    public override void SaveAll(List<B> list) { /* No change except the signature */ }
}
public enum ChosenType{
[Repo(typeof(RepA))]A=0,
[Repo(typeof(RepB))]B=1
}
公共类属性:属性{
公共repotAttribute(类型repoType){repoType=repoType;}
公共类型RepoType{get;set;}
}
班级计划
{
静态void Main()
{
ChosenType ChosenType=RandomChosenType();//A或B
//根据映射创建相应的repo实例
//添加到枚举值。
//这是一个中等昂贵的电话,还有改进的余地
//通过使用表达式树和缓存lambda表达式。
var repo=(IRepo)Activator.CreateInstance(
((RepoAttribute)typeof(ChosenType).GetMember(ChosenType.ToString())
.Single().GetCustomAttributes(typeof(RepoAttribute),false).Single()
)(1),;
var list=repo.GetAll();
回购保存全部(列表);
Console.Read();
}
静态随机_rand=新随机();
静态ChosenType随机ChosenType()
{
返回值(ChosenType)_rand.Next(0,2);
}
}
公共A类{/*无变化*/}
公共类B{/*无变化*/}
公共接口IRepo{
List GetAll();
void SaveAll(列表);
}
公共抽象类Repo:IRepo{
利斯
myDic.Add(typeof(A), new RepA());
Type t = RandomChosenType();
myDic[t].GetAll();
static void Main(string[] args)
{
    var types = Assembly.GetExecutingAssembly().Modules
        .SelectMany(m => m.GetTypes())
        .Where(t =>
            t.GetMethod("GetAll") != null &&
            t.GetMethod("SaveAll") != null &&
            t.GetMethod("GetAll").ReturnType.IsGenericType)
        .Select(t =>
            new
            {
                RepositoryType = t,
                ReturnTypeArgument = 
                    t.GetMethod("GetAll").ReturnType.GenericTypeArguments[0]
            }
            )
        .ToList();

    (new List<dynamic> { new A(), new B() }).ToList().ForEach(chosenType =>
    {
        var association = types
            .FirstOrDefault(t => 
                t.ReturnTypeArgument == chosenType.GetType());
        if (association == null)
            return;
        var repType = association.RepositoryType;
        dynamic list = repType.GetMethod("GetAll")
            .Invoke(chosenType, new object[] { });
        repType.GetMethod("SaveAll")
            .Invoke(chosenType, new object[] { list });
    });
}
public interface IRepository {
    IEnumerable<object> GetAll();
}
IEnumerable<object> IRepository.GetAll() {
    return RepA.GetAll();
}
public class GenericRepositoryExample
{

    public void Save<T>(IList<T> persons, SaveDelegate<T> save)
    {
        foreach (T person in persons)
        {
            Console.WriteLine(save(person));
        }
    }
}
public delegate string SaveDelegate<T>(T input);
public static class HelperClass
{
    public static string FrenchSave(B frenchInput)
    {

        string result = string.Format("ID = {0}; Name = {1}; City = {2}", frenchInput.Id, frenchInput.Nom, frenchInput.ville);
        return result;
    }

    public static string EnglishSave(A englishInput)
    {
        string result = string.Format("ID = {0}; Name = {1}; City = {2}", englishInput.Id, englishInput.name, englishInput.city);
        return result;
    }

}
  [Test]
    public void TestGenericRepository()
    {
        IList<A> aList = new List<A>();

        aList.Add(new A() { Id = 1, name = "George", city = "Chicago"});
        aList.Add(new A() { Id = 2, name = "Bill", city = "Toledo" });


        List<B> bList = new List<B>(); 

        bList.Add(new B() {Id= 1, Nom = "Nathalie", ville = "Paris"});
        bList.Add(new B() {Id = 2, Nom = "Michelle", ville = "Lyon"});


        GenericRepositoryExample repository = new GenericRepositoryExample();

        repository.Save<A>(aList,HelperClass.EnglishSave);

        repository.Save<B>(bList,HelperClass.FrenchSave);

    }
public enum ChosenType {
    [Repo(typeof(RepA))] A = 0,
    [Repo(typeof(RepB))] B = 1
}

public class RepoAttribute : Attribute {
    public RepoAttribute(Type repoType) { RepoType = repoType; }
    public Type RepoType { get; set; }
}

class Program
{
    static void Main()
    {
        ChosenType chosentype = RandomChosenType(); //A or B

        // Make an instance of the appropriate repo based on the mapping
        // to the enum value.
        // This is a moderately expensive call, and there's room for improvement
        // by using expression trees and caching lambda expressions.
        var repo = (IRepo)Activator.CreateInstance(
            ((RepoAttribute)typeof(ChosenType).GetMember(chosentype.ToString())
                .Single().GetCustomAttributes(typeof(RepoAttribute), false).Single()
            ).RepoType);

        var list = repo.GetAll();
        repo.SaveAll(list);

        Console.Read();
    }

    static Random _rand = new Random();
    static ChosenType RandomChosenType()
    {
        return (ChosenType)_rand.Next(0, 2);
    }
}

public class A { /* No change */ }
public class B { /* No change */ }

public interface IRepo {
    List<object> GetAll();
    void SaveAll(List<object> list);
}

public abstract class Repo<T> : IRepo {
    List<object> IRepo.GetAll() {
        return GetAll().Cast<object>().ToList();
    }

    void IRepo.SaveAll(List<object> list) {
        SaveAll(list.Cast<T>().ToList());
    }

    public abstract List<T> GetAll();
    public abstract void SaveAll(List<T> list);
}

public class RepA : Repo<A> {
    public override List<A> GetAll() { /* No change except the signature */ }
    public override void SaveAll(List<A> list) { /* No change except the signature */ }
}
public class RepB : Repo<B> {
    public override List<B> GetAll() { /* No change except the signature */ }
    public override void SaveAll(List<B> list) { /* No change except the signature */ }
}