【问题标题】:Avoid casting when accessing base class properties from a derived class从派生类访问基类属性时避免强制转换
【发布时间】:2016-09-27 04:18:04
【问题描述】:

作为 C# 的菜鸟,我正在努力寻找适合我的场景进行强制转换的最佳解决方案,基本上我试图避免从派生类中强制转换基类对象。

在我在 GridManagerBase 类中的示例中,GridTarget 属性由通用定义定义,但 SelectedTarget 使用的是基接口,从 GridManager 类需要我进行强制转换才能访问其他属性。

所以我正在尝试制定一个没有强制转换的干净解决方案。

我在网上搜索了很多示例,但无法完全得到我正在寻找的答案,所以真的在寻找任何建议。

非常感谢。

public class GridManager : GridManagerBase<IGridPoint>
{
    void DoWork()
    {
        var result = GridTarget.HasVehicle; // works

        var result2 = ((ITargetObject)SelectedTarget).SomeValue; // works with cast
    }
}

public abstract class GridManagerBase<TGridPoint> : IGridManagerBase<TGridPoint>
       where TGridPoint : class, IGridPointBase
{
    public TGridPoint GridTarget { get; protected set; }

    public ITargetObjectBase SelectedTarget { get; protected set; }

    //public IVehicleObjectBase SelectedVehicle { get; protected set; }
}

public interface IGridManagerBase<TGridPoint>
{
    TGridPoint GridTarget { get; }

    ITargetObjectBase SelectedTarget { get; }
}

public interface IGridPointBase
{
    int Row { get; }
}

public interface IGridPoint : IGridPointBase
{
    bool HasVehicle { get; }
}


public interface ITargetObjectBase
{
    int Row { get; set; }
}

public interface ITargetObject : ITargetObjectBase
{
    int SomeValue { get; }
}

更新 好的,所以我的主要目标是拥有多个 GridManager,其他对象从中具有共同的功能,所以我的想法是使用基本接口来实现这一点。

从 GridManager 中,SelectedTarget (ITargetObjectBase) 对象将具有通用逻辑,这很好,但在 GridManager 中也有独特的逻辑。

在我提出这个问题之前,我确实考虑过按照 Prasanna 建议的路线,应该提到,为什么我留下了 IVehicleObjectBase 的评论,但我不确定创建几个通用定义的指导方针.

我已经添加了一些带有具体类的附加代码,希望能更好地了解我在做什么。

public class GridManager : GridManagerBase<IGridPoint>
{
    public GridManager()
    {
        GridTarget = new GridPoint();

        SelectedTarget = new TargetObject(1, 2);
    }

    public void DoWork()
    {
        var result = GridTarget.HasVehicle; // works

        var result2 = ((ITargetObject)SelectedTarget).SomeValue; // works with cast

        SelectedTarget.DoSomeCommonWork();
    }
}

public class GridManagerB : GridManagerBase<IGridPoint>
{
    public GridManagerB()
    {
        GridTarget = new GridPoint();

        SelectedTarget = new TargetObjectB(1, string.Empty);  
    }

    public void DoWork()
    {
        var result = GridTarget.HasVehicle; // works

        var result2 = ((ITargetObjectB)SelectedTarget).SomeOtherValue; // works with cast

        SelectedTarget.DoSomeCommonWork();
    }
}

public abstract class GridManagerBase<TGridPoint> : IGridManagerBase<TGridPoint>
       where TGridPoint : class, IGridPointBase
{
    public TGridPoint GridTarget { get; protected set; }

    public ITargetObjectBase SelectedTarget { get; protected set; }

    //public IVehicleObjectBase SelectedVehicle { get; protected set; }
}

public interface IGridManagerBase<TGridPoint>
{
    TGridPoint GridTarget { get; }

    ITargetObjectBase SelectedTarget { get; }
}

public interface IGridPointBase
{
    int Row { get; }
}

public interface IGridPoint : IGridPointBase
{
    bool HasVehicle { get; }
}


public interface ITargetObjectBase
{
    int Row { get; set; }

    void DoSomeCommonWork();
}

public interface ITargetObject : ITargetObjectBase
{
    int SomeValue { get; }
}

public interface ITargetObjectB : ITargetObjectBase
{
    string SomeOtherValue { get; }
}

public abstract class TargetObjectBase : ITargetObjectBase
{
    public int Row { get; set; }

    public TargetObjectBase(int row)
    {
        Row = row;
    }

    public void DoSomeCommonWork()
    {
        Console.WriteLine(Row.ToString());
    }
}

public class TargetObject : TargetObjectBase, ITargetObject
{
    public int SomeValue { get; private set; }

    public TargetObject(int row, int some)
        : base(row)
    {
        SomeValue = some;
    }
}

public class TargetObjectB : TargetObjectBase, ITargetObjectB
{
    public string SomeOtherValue { get; private set; }

    public TargetObjectB(int row, string other)
        : base(row)
    {
        SomeOtherValue = other;
    }
}

public class GridPoint : IGridPoint
{
    public int Row { get; set; }

    public bool HasVehicle { get; set; }
}

所以我认为我最好的两个选择是要么采用通用定义路线,要么从 GridManagerBase 中删除 ITargetObjectBase 属性,然后将 ITargetObject 放在 IGridManager 接口中。

【问题讨论】:

  • 几乎唯一的方法就是把它变成一个泛型。有理由不这样做吗?
  • 不清楚你想用代码实现什么。
  • 同意@ShaunLuttin,请提供一个包括演员表的当前用法示例,以及没有演员表的所需用法。

标签: c# casting


【解决方案1】:
  • GridTarget 不需要强制转换的原因是:它是 IGridPoint 类型的直接包含定义 HasVehicle
  • SelectedTarget 是类型 ITargetObjectBaseITargetObjectBase 不直接包含 SomeValue 的定义。所以ITargetObject 的演员表是 需要。
  • SelectedTarget.Row 中不需要强制转换,因为 ITargetObjectBase 包含 Row 的定义。

在您的情况下,您可以将IGridManagerBase 设置为具有两个泛型参数的类型,如下所示。然后你可以打电话给SelectedTarget.SomeValue而不用演员表

public class GridManager : GridManagerBase<IGridPointA, ITargetObject>
{
    void DoWork()
    {
        var result = GridTarget.HasVehicle; // works
        var result2 = SelectedTarget.SomeValue; // works with cast
    }
}
public abstract class GridManagerBase<TGridPoint, TTargetObject> : IGridManagerBase<TGridPoint,TTargetObject> 
  where TGridPoint : class, IGridPointBase
  where TTargetObject : class, ITargetObjectBase
{
    public TGridPoint GridTarget { get; protected set; }
    public TTargetObject SelectedTarget { get; protected set; }
    //public IVehicleObjectBase SelectedVehicle { get; protected set; }
}
public interface IGridManagerBase<TGridPoint, TTargetObject>
{
    TGridPoint GridTarget { get; }
    TTargetObject SelectedTarget { get; }
}
public interface IGridPointBase
{
    int Row { get; }
}
public interface IGridPoint : IGridPointBase
{
    bool HasVehicle { get; }
}
public interface IGridPointA : IGridPointBase
{
    bool HasVehicle111 { get; }
}
public interface ITargetObjectBase
{
    int Row { get; set; }
}
public interface ITargetObject : ITargetObjectBase
{
    int SomeValue { get; }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多