【问题标题】:Cast base class to derive class in .NET Core将基类转换为 .NET Core 中的派生类
【发布时间】:2020-06-07 08:35:39
【问题描述】:

我想创建一个类来调用我的 SQL Server 中的存储过程。我将 C# 与 .NET Core 3.1 一起使用。所有存储过程都返回相同的结果,但在某些情况下,我必须做更多的活动,然后每个函数都有自己的基于基类的返回类型,在下面的代码中称为 BaseResponse

public class BaseResponse
{
    public int ErrorCode { get; set; }
    public string Message { get; set; }
}

public class InvoiceResponse : BaseResponse
{
    public bool IsPaid { get; set; }
}

然后,我有我的BaseCall,它负责调用存储过程并返回BaseResponse

public async Task<BaseResponse> BaseCall(string procedureName, string[] params)
{
    BaseResponse rtn = new BaseResponse();

    // call SQL Server stored procedure

    return rtn;
}

在另一个类中,我想将 BaseResponse 与派生类一起转换。为此,我认为我可以将 BaseResponse 与派生类一起转换,但我错了。

public async Task<InvoiceResponse> GetInvoice(int id)
{
    InvoiceResponse rtn = new InvoiceResponse();
    BaseResponse response = BaseCall("myprocedure", null);
    rtn = (InvoiceResponse)response;

    // do something else

    return rtn;
}

我看到了另外两个帖子(Convert base class to derived classthis one),我明白我不能按照我想要的方式投射。然后我就是我的延伸

/// <summary>
/// Class BaseClassConvert.
/// </summary>
public static class BaseClassConvert
{
    /// <summary>
    /// Maps to new object.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="sourceobject">The sourceobject.</param>
    /// <returns>T.</returns>
    /// <remarks>
    /// The target object is created on the fly and the target type
    /// must have a parameterless constructor (either compiler-generated or explicit)
    /// </remarks>
    public static T MapToNewObject<T>(this object sourceobject) where T : new()
    {
        // create an instance of the target class
        T targetobject = (T)Activator.CreateInstance(typeof(T));

        // map the source properties to the target object
        MapToExistingObject(sourceobject, targetobject);

        return targetobject;
    }

    /// <summary>
    /// Maps to existing object.
    /// </summary>
    /// <param name="sourceobject">The sourceobject.</param>
    /// <param name="targetobject">The targetobject.</param>
    /// <remarks>The target object is created beforehand and passed in</remarks>
    public static void MapToExistingObject(this object sourceobject, object targetobject)
    {
        // get the list of properties available in source class
        var sourceproperties = sourceobject.GetType().GetProperties().ToList();

        // loop through source object properties
        sourceproperties.ForEach(sourceproperty =>
        {
            var targetProp = targetobject.GetType().GetProperty(sourceproperty.Name);

            // check whether that property is present in target class and is writeable
            if (targetProp != null && targetProp.CanWrite)
            {
                // if present get the value and map it
                var value = sourceobject.GetType().GetProperty(sourceproperty.Name).GetValue(sourceobject, null);
                targetobject.GetType().GetProperty(sourceproperty.Name).SetValue(targetobject, value, null);
            }
        });
    }
}

此代码有效,我可以像这样使用它:

public async Task<InvoiceResponse> GetInvoice(int id)
{
    InvoiceResponse rtn = new InvoiceResponse();
    BaseResponse response = BaseCall("myprocedure", null);
    response.MapToExistingObject(rtn);

    // do something else

    return rtn;
}

我的问题是:

  • 在 .NET Core 中是否有更有效的方法将基类转换为派生类?
  • 这是铸造的最佳做法吗?
  • 还有其他指南吗?
  • 此过程使用Reflection。从性能的角度来看,这是实现此演员阵容的正确且最便宜的方式吗?

【问题讨论】:

  • 我对这个前提感到困惑。如果BaseCall 不知道派生类型(它似乎并不知道),那么它甚至无法传递来自存储过程的信息,这些信息将允许稍后构造更多派生类型。如果它确实知道它们,那么它可以立即构建它们。而且,如果不需要额外信息来构造派生类型,那么您可以简单地在所有接受基类型实例并从中复制的派生类型上使用构造函数。
  • 也可能是the case,您不想为数据库响应提供自己的类并使用实体框架等 ORM 框架。
  • 我没有得到你的评论。 BaseCall 是一个调用存储过程并从它们接收结果的类。谁在调用BaseClass 具有基于BaseResponse 以及其他一些字段的自己的返回类型。我不想使用AutoMapper(例如)将每个字段从BaseResponse 映射到派生类。
  • 我使用Entity Framework调用存储过程并获取结果。
  • Who is calling the BaseClass has its own return type based on the BaseResponse plus some other fields - 如果BaseResponse 没有从数据库中返回这些其他字段,那么调用者将如何获取这些字段?

标签: c# .net-core base-class .net-core-3.1


【解决方案1】:

如果此实例实际上没有继承它,则您不能 cast(不出错)将返回/包含基类实例的表达式返回/包含任何继承者类型(并且要检查这一点,C# 中有 type-testing operators )。转换为docs 状态是编译器尝试在运行时执行显式转换。此外,正如您所提到的,您无法实现从基类或到基类的自定义显式转换。

您在寻找(并尝试做)什么称为映射,有很多库可以用于此目的,包括但不限于 AutomapperMapsterExpressMapper,例如。

【讨论】:

  • 当我使用派生类强制转换 BaseResponse 时出现错误。我正在更新帖子。
  • @Enrico 您永远不能将基类强制转换为派生类。您所做的甚至不称为强制转换,它正在创建一个不相关的实例并用数据填充它。也就是说,您开发了自己的自动映射器 - you said 您不想使用它,即使您正在使用它。
猜你喜欢
  • 2017-01-08
  • 2013-11-17
  • 1970-01-01
  • 2021-02-18
  • 2017-07-18
  • 2011-02-04
  • 2012-09-15
相关资源
最近更新 更多