C# 从派生类获取特定类型

C# 从派生类获取特定类型,c#,asp.net-mvc,inheritance,polymorphism,covariance,C#,Asp.net Mvc,Inheritance,Polymorphism,Covariance,简介:我正在创建一个MVC应用程序,需要在其中显示各种类型的文档,其中一些文档包含比其他文档更多的作者信息 我想做的事:我的方法是拥有一个通用的“查看文档”视图,它以传递给它的对象的形状/类型指定的格式动态显示文档 示例:一个简单文档将加载到SimpleDocumentViewModel中,并显示为这样。但是,我想将一个更大类型的文档加载到ExtendedDocumentViewModel中,并附带有关文档和作者的附加信息。然后,视图将根据其接收的对象显示相应的数据 我现在所处的位置:在这种情况

简介:我正在创建一个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; }
}
问题:所以我的问题是;如何最好地从完全实现的类中获取特定类型,或者需要返回基本类型并在视图中查询所有类型?还是我疯了,需要回到绘图板上

编辑:

我知道这一点,但希望有另一种方法返回/标识派生类型,这样我就不必在视图中查询所有派生类型


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

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

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

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

可能的清理选项是在名为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();
}
第二项建议:

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

我可能有点离谱,但我理解你的问题。。。为什么不在对象中抛出返回类型并将其传递给视图

您可以查看所需的方法,并使用反射提取所需的任何信息。修改此选项,对象类将保留您想要的内容

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;
    }
}
公共类DiscoverInternalClass
{
公共列表FindClassMethods(类型)
{
列表方法列表=新列表();
MethodInfo[]MethodInfo=type.GetMethods();
foreach(MethodInfo中的MethodInfo m)
{
List propTypeList=新列表();
List propNameList=新列表();
字符串returntype=m.returntype.ToString();
foreach(m.GetParameters()中的变量x)
{
propTypeList.Add(x.ParameterType.Name);
propNameList.Add(x.Name);
}
InternalClassObject ICO=新的InternalClassObject(c.Name、propNameList、propTypeList);
方法列表。添加(ICO);
}
返回方法列表;
}
}
对象类可以是这样的,也可以根据需要进行修改:

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;
    }
}
公共类InternalClassObject
{
公共字符串名称{get;set;}
公共列表参数NameList{get;set;}
公共列表参数列表{get;set;}
公共InternalClassObject(字符串名称、列表IPParameterNameList、列表IPParameterList)
{
Name=iName;
ParameterNameList=IPParameterNameList;
ParameterList=IPParameterList;
}
}
您可以使用所需的类调用这样的方法

public static List<InternalClassObject> MethodList = new List<InternalClassObject>();

DiscoverInternalClass newDiscover= new DiscoverInternalClass();
MethodList = newDiscover.FindClassMethods(typeof(ExtendedDocumentViewModel));
public static List MethodList=new List();
DiscoverInternalClass newDiscover=新DiscoverInternalClass();
MethodList=newDiscover.FindClassMethods(typeof(ExtendedDocumentViewModel));
现在,您可以基于MethodList中的内容构建GetView


希望这有帮助

感谢您的回复,我知道这一点,并打算在必要时使用它。然而,这个问题的目标是尝试以更好的方式返回/标识这些派生类型,以便我尽可能少地使用它们。我知道C#不支持返回型协方差,但希望有另一种解决方法。我认为这基本上是正确的答案,我是个白痴。我想让对象的动态类型决定它的显示方式,但不想对所有内容进行动态类型检查。。。事后看来,我可能不能没有一个。啊!我会继续调查,但我认为你已经一针见血了。再次感谢!:)谢谢你的建议,它们看起来很有趣,但我不认为这对我有帮助。在我的例子中,每个文档都以几乎相同的方式显示,它们都是相同类型的文档。(它们不是真正的文档,这只是一种混淆)在某些类型的文档中,我需要显示有关作者的其他信息。大部分其他的东西都会在同一个地方,但是添加了新的作者数据。不同类型的文档将显示不同的附加信息集。