在通过接口公开的方法上使用动态返回类型在架构上是错误的吗?

Yog*_*raj 2 c# architecture dynamic

我有一个使用业务逻辑层中的接口公开的方法.它如下:

  public interface IMyWorkingClass
  {
       IEnumerable<dynamic> GetSomeList(); 
  }

  public class MyWorkingClass : IMyWorkingClass
  {
      public IEnumerable<dynamic> GetSomeList()
      {  
           dynamic foos = new List<dynamic>();

           dynamic item = new ExpandoObject();

           item.PropOne = (new Foo()).FooPropertyOne;

           item.PropTwo = (new Bar()).BarPropertyOne;

           foos.Add(item);

           return foos;

      }
  }  

  public class Foo
  {
      public int FooId{get;set;}
      public string FooPropertyOne{get;set;}
      public string FooPropertyTwo{get;set;}

  }

  public class Bar 
  {
      public int BarId{get;set;}
      public string BarPropertyOne{get;set;}
      public string BarPropertyTwo{get;set;}

  }
Run Code Online (Sandbox Code Playgroud)

关于动态本身有很多不同的意见/偏好.我觉得它们很有用.我的一位朋友说动力学很好,但上面的方式不是.提出的论点是编译器不会捕获动态对象上发生的变化.我认为单元测试能够抓住那些.所以我不同意.你的专家意见是什么?提前致谢 :)

更新

这里有点清楚(希望)代码:

public interface IMyWorkingClass
{
    IEnumerable<dynamic> GetListOfClassesForStudentDynamicReturn();
    IEnumerable<StudentClassInfo> GetListOfClassesForStudentStaticReturn();

}

public class MyWorkingClass : IMyWorkingClass
{
    public IEnumerable<dynamic> GetListOfClassesForStudentDynamicReturn(Student student)
    {
        dynamic listOfClasses = new List<dynamic>();



         // repository pattern is used in DAL  
        var datafromDB = (StudentCollegeClassRepo.GetQueryable(x=>x.StudentId==student.StudentId)
                          .select(item => new {
                              item.CollegeClassId
                              ,item.CollegeClass.CollegeClassName
                              ,item.IsEnabledForStudent
                          }).ToList();

        foreach (var item in datafromDB)
        {
            dynamic classWithStudent = new ExpandoObject();
            classWithStudent.CollegeClassId = item.CollegeClassId;
            classWithStudent.CollegeClassName = item.CollegeClassName;
            classWithStudent.IsEnabledForStudent = item.IsEnabledForStudent;
            listOfClasses.Add(studentWithClass);
        }


        return listOfClasses;

    }

    public IEnumerable<StudentClassInfo> GetListOfClassesForStudentStaticReturn(Student student)
    {
         // repository pattern is used in DAL  
        var datafromDB = (StudentCollegeClassRepo.GetQueryable(x=>x.StudentId==student.StudentId)
                          .select(item => new StudentClassInfo {
                              CollegeClassId = item.CollegeClassId
                              ,CollegeClassName = item.CollegeClass.CollegeClassName
                              ,IsEnabledForStudent = item.IsEnabledForStudent
                          }).ToList();


        return datafromDB;

    }
}
// this class is like a viewmodel
public class StudentClassInfo
{
    public int CollegeClassId { get; set; }
    public string CollegeClassName { get; set; }
    public bool IsEnabledForStudent { get; set; }
}

public class Student
{
    public int StudentId { get; set; }
    public string StudentName { get; set; }
}

public class StudentCollegeClass
{
    public int StudentId { get; set; }
    public int CollegeClassId { get; set; }
    public bool IsEnabledForStudent { get; set; }
}

public class CollegeClass
{
    public int CollegeClassId { get; set; }
    public string CollegeClassName { get; set; }


}
Run Code Online (Sandbox Code Playgroud)

希望我现在能让事情变得更加清晰.那么,动态返回的方法是正确的还是创建一个静态类型并返回?我也在这里学习如何正确提问.感谢您的耐心和真棒回复:)

Lig*_*ker 6

那么,你想创建一个接口来揭示一个返回未知的方法IEnumerable吗?IEnumerble在这种情况下使用泛型版本是否有直接优势除了保存一些转换/测试/重载之外,如果要在返回方法后使用这些对象,则无论如何都必须这样做?

虽然我不会争论dynamic在某些情况下可能有用.在我看来,它经常会出现一个设计缺陷.我每次来使用它时,我都会坐下来想想我是否真的需要它.大多数时候,我得出的结论是,通过一些简单的改变,我可以消除它并制作更清洁的设计.

在这种情况下,您真的需要具有动态的泛型类型吗?我的第一个也是快速猜测,你可以使用非泛型IEnumerable.

或者如果你想保存一些铸件,并且你有不同的元素,你可以找到所有元素的共同点.我现在看到了,你所有的财产都是字符串.或者,如果要返回元素组合,可以使用一些元素Tuple<>

如果你真的最终返回一个完整的未知类型的很多不同的对象,你可以使用IEnumerable<object>,但后来我会质疑该接口实现的存在的原因.我不记得曾经创建过一个接口,它会在不同的实现之间,甚至在单个实现中,绝对存在任何类型的共同点.它可以控制,数字,组件,实体......但他们倾向于分享一些东西.如果它的属性,你甚至可以包装一些PropertyInfo!

TL:DR; 除非您能够提出一个非常明确的案例,即这种设计模式将用于任何其他方式无法避免的非常具体的目的,我建议不要使用它.我IEnumerable2美分.


小智 6

尽管Skeet说的话:)我会在这里添加一些想法.

如果您开始使用Dynamics的路径,您必须转变思路.你不知道你的对象什么,你只关心它能做什么.

你发现自己不需要很快地接口 - 然后你会问自己"我还在做什么?" 这总是一个很好的问题.

然后当你开始编写更多测试以掩盖编译器检查丢失时发生转换 - 你开始更清楚地编写方法.你开始依赖工厂和其他类来在这些无定形的动态粘性物质之上强加逻辑.

如果你考虑心理转变,这是令人难以置信的自由.例如,你有一个"MyWorkingClass",可以在Foo/Bar之上执行某些操作.如果那是一个名为"仓库"的履行类,它有一些叫做"CheckInvetoryOf(动态项目)"的方法 - 事情开始变得更有意义了.

在现实世界中,您将在此处发送一个接口 - 可能是ITrackable或其他东西 - 暴露了可以使用的非常小的子集.它会起作用,但如果你后来改变了你的方法并希望仓库发送数字商品 - 比如下载?

你的仓库课程可能是用实体制作的 - 然后转向发送数字下载......哦不!

但如果你使用动力学 - 这很容易.您可以简单地询问该项目是否是IDigitalGood(例如)并且处理得很好.

所以 - 你写的代码是,令人困惑.如果您花一些时间使用动态语言,它将为您提供心理转变,使其不那么令人困惑.

哦 - 就"建筑错误"而言,做你做过的事......谁知道呢.如果它令人困惑,那就不好了.如果它使测试变得困难 - 这三倍不好.如果你被嘲笑,你可能会走上正轨:)