2

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

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

  }

关于动态本身有很多不同的意见/偏好。我觉得它们很有用。我的一位朋友说动态很好,但上面的使用方式却不是。提出的论点是编译器不会捕获动态对象上更改的内容。我认为单元测试将能够捕捉到这些。所以我不同意。你的专家意见是什么?提前致谢 :)

更新

这是更清晰(希望)的代码:

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


}

希望我现在让事情变得更清楚了。那么,动态返回的方法是可以的还是创建一个静态类型并返回它呢?我也在学习如何在这里正确提问。谢谢你的耐心和很棒的回复:)

4

2 回答 2

6

那么,您想创建一个接口来公开一个返回未知的方法IEnumerable吗?在这种情况下,除了保存一些强制转换/测试/重载之外,如果您想在方法返回后使用这些对象,那么在这种情况下使用通用版本是否有直接的优势IEnumerble

虽然我不会争辩这dynamic在某些情况下会很有用。在我看来,它经常显示出设计缺陷。每次来用的时候,其实我都坐下来想是不是真的需要它。大多数时候,我得出的结论是,通过一些简单的更改,我可以消除它并做出更简洁的设计。

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

或者,如果你想节省一些演员表,并且你有不同的元素,你可以找到所有元素的共同点。我现在看到,你所有的财产都是字符串。或者如果你想返回元素的组合,你可以使用一些Tuple<>

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

TL:博士;除非您能提供一个非常明确的案例,说明此设计模式将服务于任何其他方式都无法避免的非常特定的目的,否则我建议您不要使用它。我IEnumerable的 2 美分。

于 2012-11-15T22:28:17.510 回答
6

尽管 Skeet 说了什么 :) 我会在这里添加一些想法。

如果你开始使用 Dynamics,你必须转变你的想法。你不知道你的对象什么,你只关心它能做什么

你发现自己很快就不需要接口了——然后你问自己“我到底在做什么?”。这总是一个很好的问题。

然后,当您开始编写更多测试以掩盖编译器检查的损失时,发生了转变——您开始更清楚地编写方法。您开始依赖工厂和其他类在这些无定形的动态粘液上施加逻辑。

如果你考虑到精神上的转变,那真是令人难以置信的自由。例如,您有一个在 Foo/Bar 之上执行某些操作的“MyWorkingClass”。如果那是一个名为“Warehouse”的实现类,它有一些名为“CheckInvetoryOf(dynamic item)”的方法——事情就开始变得更有意义了。

在现实世界中,您将在此处发送一个接口(可能是 ITrackable 或其他东西),它公开了可以使用的非常小的子集。它会起作用,但如果您稍后改变方法并希望 Warehouse 运送数字商品——比如下载,该怎么办?

您的 Warehouse 课程可能是仿照实体店设计的 - 并且正在转向发送数字下载……哦,不!

但是,如果您使用动态 - 这很容易。您可以简单地询问该项目是否是 IDigitalGood(例如)并很好地处理它。

所以 - 你写的代码是,是的,令人困惑。如果你花一些时间在动态语言上,它会给你精神上的转变,让它不那么混乱。

哦 - 就“架构上的错误”而言,做你所做的......谁知道呢。如果它令人困惑,那就不好了。如果它使测试变得困难 - 那是三倍不好。如果你被嘲笑,你可能是在正确的轨道上:)

于 2012-11-15T22:45:57.653 回答