Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/297.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#_Generics_Interface - Fatal编程技术网

C# 当泛型类型取决于从何处调用时,为类创建泛型接口

C# 当泛型类型取决于从何处调用时,为类创建泛型接口,c#,generics,interface,C#,Generics,Interface,我试图创建一个通用接口,该接口可以由需要能够返回Class1或Class2类型列表的类实现。我一直无法实现这一点,因为我需要传入IRules泛型类型,如果传入ClassAbstract,我会遇到下面的问题,这是一个非常简短的泛型示例,说明了我真正要处理的问题,其中一个属性只是派生类型中的一个,而不是基类型 我不知道如何才能让它以我想要的方式工作,基本上在那一节中,我可以检查列表的类型,然后指定要做什么,但问题是,因为我将ClassAbstract作为泛型参数传递,这也不起作用……有没有一种方法可

我试图创建一个通用接口,该接口可以由需要能够返回Class1或Class2类型列表的类实现。我一直无法实现这一点,因为我需要传入IRules泛型类型,如果传入ClassAbstract,我会遇到下面的问题,这是一个非常简短的泛型示例,说明了我真正要处理的问题,其中一个属性只是派生类型中的一个,而不是基类型

我不知道如何才能让它以我想要的方式工作,基本上在那一节中,我可以检查列表的类型,然后指定要做什么,但问题是,因为我将ClassAbstract作为泛型参数传递,这也不起作用……有没有一种方法可以让它正常工作而不必指定接口键入,因为我实际上不知道它是一个Class1列表还是一个Class2列表,它是基于从哪里调用的?很明显,我可以复制代码,只对每个类类型使用一次方法,但是代码太多了,我不认为这应该很难做到我想做的事情,但也许我错了

public interface IRules<T> {
List<T>GetAdditionalPropRules(List<T> list1);
List<T>SetAdditionalPropRules(List<T> list1);
}

public ClassAbstract {
  public string NAME {get;set;}
  public string AGE {get;set;}
}

public class Class1: ClassAbstract {
  public string JOB {get;set;}
}

public class Class2: ClassAbstract {

}

public class Rules MyProperties: IRules<ClassAbstract>{ **<--- I Want this to be able to accept either Class1 or Class2**
  public List<ClassAbstract> SetAdditionalPropRules(List<ClassAbstract> myList) {
    foreach(dynamic item in myList) {
      if(item.NAME == "Joe") {
        myList.Add(new ClassAbstract {
          AGE = 30,
          JOB = "Tester" **<--- ISSUE RIGHT HERE -- ClassAbstract Does not have property JOB**
}
}
}
}
}

也许,像这样如果您的Class1和Class2基于某个接口:

     interface IClassAbsract
         {
             string Name { get; set; }
             string Age { get; set; }
         }
         public class Class1: IClassAbsract
         {
             public string Name { get; set; }
             public string Age { get; set; }
         }
         public class Class2 : IClassAbsract
         {
             public string Name { get; set; }
             public string Age { get; set; }
         }

         public class ListRule
         {
             public List<IClassAbsract> List { get; set; } = new List<IClassAbsract>();
         }
然后,以后,可以这样使用:

            ...
     ...
     //populate list with testing instances
     var list = new ListRule();
     var c1 = new Class1() { Name = "Class #1", Age = "11" };
     list.List.Add(c1);

     var c2 = new Class2() { Name = "Class #2", Age = "22" };
     list.List.Add(c2);

     ...
     //then, get only certain types, and populate second list "myList": for example, pull only of type Class1:
     public  void Test2(List<IClassAbsract> list)
     {
             if (list == null || !list.Any())
             {
                     throw new System.ArgumentNullException("empty");
             }
             //pull only of type Class1:
             List<IClassAbsract> myList = new List<IClassAbsract>();
             myList.AddRange(list
                    .Where(e => e is Class1)
                     .Select(e => new Class1() { Age = e.Age, Name = "Joe" })
                     .ToList()
             );
    }
这对你有帮助吗

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApp
{

  static partial class Program
  {

输出:

Joe / Class1 : 20 ()
Joe / Class2 : 25
John / Class1 : 30 ()
John / Class2 : 35

Joe / Class1 : 30 (Tester)
Joe / Class2 : 25
John / Class1 : 30 ()
John / Class2 : 35

你把泛型和动态混合在一起了。它们代表着完全相反的概念。我强烈建议您不要使用这种解决方案。在这里,您可以添加一个新的类1。因为Class1和Class2都继承ClassAbstract,所以它们都是ClassAbstract。与您的问题无关,但是在foreach循环中用var代替dynamic更为正确。您的问题不清楚。您试图编写的方法在列表上运行。不清楚为什么每个叫乔的人都一定是测试人员。也就是说,如果您想设置JOB属性,并且该属性只存在于Class1类中,那么当然需要创建Class1的新实例。那么,为什么不这样做呢?为什么要使用新的ClassAbstract而不是新的Class1?请改进您的问题,使其有意义。如果作业属性接收到Class1,您似乎希望设置AdditionalProjectRules来设置作业属性。如果是2级,你想做什么?如果它应该做一些不同的事情,它不是通用的。泛型方法适用于对各种类型执行相同操作,在这种情况下,您希望根据类型执行不同操作。不起作用…无法通过引用转换、装箱转换、取消装箱转换、换行转换或空类型转换将类型“System.Collections.generic.List”转换为“Class1”。我将放弃这种方式…可能不是一个好主意,我只是讨厌复制这么多代码,因为实际上只有两行。它必须工作。答案更新为完整的文件代码和测试。我使用了您的代码,但您应该重构它,并将RulesMyProperties类设置为静态,因为它似乎是一个助手。
    static void Test()
    {
      var rules = new RulesMyProperties();
      var list = new List<ClassAbstract>();
      list.Add(new Class1 { NAME = "Joe", AGE = 20 });
      list.Add(new Class2 { NAME = "Joe", AGE = 25 });
      list.Add(new Class1 { NAME = "John", AGE = 30 });
      list.Add(new Class2 { NAME = "John", AGE = 35 });
      Action print = () =>
      {
        foreach ( var item in list )
        {
          Console.Write($"{item.NAME} / {item.GetType().Name} : {item.AGE}");
          if ( item is Class1 )
            Console.Write($" ({((Class1)item).JOB})");
          Console.WriteLine();
        }
      };
      print();
      rules.SetAdditionalPropRules(list);
      Console.WriteLine();
      print();
    }
  }
  public class RulesMyProperties : IRules<ClassAbstract>
  {

    public List<ClassAbstract> SetAdditionalPropRules(List<ClassAbstract> myList)
    {
      foreach ( var item in myList.ToList() )
      {
        if ( item != null )
          if ( item.NAME == "Joe" )
          {
            if ( item is Class1 )
            {
              ( item as Class1 ).AGE = 30;
              ( item as Class1 ).JOB = "Tester";
            }
            else
            {
              myList.Remove(item);
              myList.Add(new Class1
              {
                NAME = "Joe",
                AGE = 30,
                JOB = "Tester"
              });
            }
            break;
          }
      }
      return myList;
    }

    public List<ClassAbstract> GetAdditionalPropRules(List<ClassAbstract> list1)
    {
      throw new NotImplementedException();
    }

  }
  public interface IRules<T>
  {
    List<T> GetAdditionalPropRules(List<T> list1);
    List<T> SetAdditionalPropRules(List<T> list1);
  }
  public class ClassAbstract
  {
    public string NAME { get; set; }
    public int AGE { get; set; }
  }
  public class Class1 : ClassAbstract
  {
    public string JOB { get; set; }
  }
  public class Class2 : ClassAbstract
  {

  }
}
Joe / Class1 : 20 ()
Joe / Class2 : 25
John / Class1 : 30 ()
John / Class2 : 35

Joe / Class1 : 30 (Tester)
Joe / Class2 : 25
John / Class1 : 30 ()
John / Class2 : 35