【问题标题】:Get specific type from derived class从派生类中获取特定类型
【发布时间】:2018-06-12 15:54:03
【问题描述】:

简介:我正在创建一个 MVC 应用程序,我需要在其中显示各种类型的文档,其中一些包含比其他更多的作者信息。

我想做的事:我的方法是有一个通用的“查看文档”视图,它以传递给它的对象的形状/类型规定的格式动态显示文档。

示例:一个简单的文档将被加载到 SimpleDocumentViewModel 中,并显示为这样。但是,我想将更大类型的文档加载到 ExtendedDocumentViewModel 中,并附带有关文档和作者的附加信息。然后,视图将根据其接收到的对象显示适当的数据。

我现在所处的位置:本着这种精神,我创建了以下接口和类,但我不知道如何在其派生中返回/识别更具体的返回类型类。

abstract class BaseDocumentViewModel : DocumentViewModel, IDocumentViewModel
{
    public int DocumentId { get; set; }
    public string Body { get; set; }
    public IAuthorViewModel Author { get; set; }
}

class SimpleDocumentViewModel : BaseDocumentViewModel
{
}

class ExtendedDocumentViewModel : BaseDocumentViewModel
{
    public new IAuthorExtendedViewModel Author { get; set; }
}

interface IAuthorViewModel
{
    int PersonId { get; set; }
    string Name { get; set; }
}

interface IAuthorExtendedViewModel : IAuthorViewModel
{
    int ExtraData { get; set; }
    int MoreExtraData { get; set; }
}

问题:所以我的问题是;如何最好地从完全实现的类中获取特定类型,或者我是否需要返回基本类型并在视图中全部查询?还是我疯了,需要回到绘图板上?

编辑:

我知道c# doesn't support return type covarience,但希望可能有另一种方法来返回/识别派生类型,这样我就不必在视图中查询它们。

我当前的解决方案是始终返回基本类型,并为每个具体类型提供一个单独的视图,该视图只是将每个对象转换为正确的类型,只查询可能不同的那些。或许这是最好的解决方案结束了,但感觉很不雅。

【问题讨论】:

    标签: c# asp.net-mvc inheritance polymorphism covariance


    【解决方案1】:

    通常你可以做一个简单的“是”检查。因此,您可以在视图中进行条件渲染,例如:

    @if(Model is ExtendedDocumentViewModel)
    {
      // render ExtendedDocumentViewModel html here
    }
    

    类型检查通常被认为是一种反模式,但是我不确定是否有更好的方法来解决这个问题。如果您使用的是 .NET Core,您还可以在此处查看子类标记 http://examples.aspnetcore.mvc-controls.com/InputExamples/SubClass

    【讨论】:

    • 感谢您的回复,我知道这一点,并打算在必要时使用它。然而,这个问题的目标是尝试以更好的方式返回/识别这些派生类型,以便我尽可能少地使用它。我知道 C# 不支持返回类型协方差,但希望可能有另一种方法。
    • 我认为这基本上是正确的答案,而且我是个白痴。我想让一个对象的动态类型决定它的显示方式,但不想动态类型检查所有内容......事后看来,我可能不能没有另一个。嗬!现在将继续调查,但认为你已经一针见血了。再次感谢! :)
    【解决方案2】:

    可能的更清洁选项是在名为 GetView 的接口中仅具有一个签名,每个文档都必须实现该签名。这样,每个文档类型都有自己的实现函数的方式,调用函数知道每个文档都有一个函数 GetView。如果每个文档都有独特的查看文档的方式,则此方法将很有效。但是,如果某些文档共享相同的视图获取方式,那么我可以建议将每个视图类型创建到它们自己的类中,并且您可以将视图类型分配给每个文档。我建议研究策略模式。

    第一个建议:

    class SimpleDocumentViewModel : IAuthorViewModel
    {
          view GetView()
          {
              ... do document specific stuff
              ... return view
          }
    }
    
    class ExtendedDocumentViewModel : IAuthorViewModel
    {
          int ExtraData { get; set; }
          int MoreExtraData { get; set; }
    
          view GetView()
          {
              ... do document specific stuff
              ... return view
          }
    }
    
    interface IAuthorViewModel
    {
        view GetView();
    }
    

    第二个建议:

    class SimpleDocumentViewModel : IAuthorViewModel
    {
          public viewType1 view {get;set;}
    
          public SimpleDocumentViewModel(viewType1 viewIn,etc...)
          {
              view = viewIn;
          } 
          view GetView()
          {
              return view.GetView();
          }
    }
    
    class ExtendedDocumentViewModel : IAuthorViewModel
    {
          int ExtraData { get; set; }
          int MoreExtraData { get; set; }
          public viewType2 view {get;set;}
    
          public ExtendedDocumentViewModel(viewType2 viewIn,etc...)
          {
              view = viewIn;
          } 
          view GetView()
          {
              return view.GetView(ExtraData,MoreExtraData);
          }
    }
    
    interface IAuthorViewModel
    {
        view GetView();
    }
    

    【讨论】:

    • 感谢您的建议,它们看起来很有趣,但认为这对我没有帮助。在我的例子中,每个文档都以几乎相同的方式显示,并且它们都是同一种文档。 (它们不是真正的文档,这只是一种混淆)在某些类型的文档中,我需要显示有关作者的其他信息。大多数情况下,其他所有内容都将在同一个地方,但添加了这个新的作者数据。不同类型的文档需要显示不同的附加信息集。
    【解决方案3】:

    我在这里可能有点离题,但据我了解您的问题...为什么不直接将返回类型放入一个对象并将其传递给您的视图?

    您可以查看所需的方法并使用反射来提取您想要的任何信息。修改它,对象类就会保存你想要的任何东西。

    public class DiscoverInternalClass
    {
        public List<InternalClassObject> FindClassMethods(Type type)
        {
            List<InternalClassObject> MethodList = new List<InternalClassObject>();
    
            MethodInfo[] methodInfo = type.GetMethods();
    
            foreach (MethodInfo m in methodInfo)
            {
                List<string> propTypeList = new List<string>();
                List<string> propNameList = new List<string>();
    
                string returntype = m.ReturnType.ToString();
    
                foreach (var x in m.GetParameters())
                {
                    propTypeList.Add(x.ParameterType.Name);
                    propNameList.Add(x.Name);
    
                }
                InternalClassObject ICO = new InternalClassObject(c.Name, propNameList, propTypeList);
                MethodList.Add(ICO);
            }
            return MethodList;
        }
    }
    

    对象类可以是这样的,也可以根据需要进行修改:

    public class InternalClassObject
    {
        public string Name { get; set; }
        public List<string> ParameterNameList { get; set; }
        public List<string> ParameterList { get; set; }
    
        public InternalClassObject(string iName,List<string> iParameterNameList, List<string> iParameterList)
        {
            Name = iName;
            ParameterNameList = iParameterNameList;
            ParameterList = iParameterList;
        }
    }
    

    您可以使用所需的类调用这样的方法。

    public static List<InternalClassObject> MethodList = new List<InternalClassObject>();
    
    DiscoverInternalClass newDiscover= new DiscoverInternalClass();
    MethodList = newDiscover.FindClassMethods(typeof(ExtendedDocumentViewModel));
    

    现在您可以根据 MethodList 中的内容构建您的 GetView

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-30
      • 1970-01-01
      • 2015-03-30
      • 1970-01-01
      • 2010-11-01
      • 1970-01-01
      • 2018-11-19
      • 2011-05-24
      相关资源
      最近更新 更多