简体   繁体   English

从派生类访问基类属性时避免转换

[英]Avoid casting when accessing base class properties from a derived class

As a noob to C# I'm struggling to wrap my head around the best solution for casting with my scenario, basically I'm trying to avoid casting base class objects from a derived class. 作为C#的新手,我正竭尽全力地围绕用自己的方案进行铸造的最佳解决方案,基本上,我试图避免从派生类中铸造基类对象。

In my example within GridManagerBase class the GridTarget property is defined by the generic definition, but the SelectedTarget is using a base interface, which from with the GridManager class requires me to cast to gain access to additional properties. 在我的GridManagerBase类中的示例中,GridTarget属性是由通用定义定义的,但是SelectedTarget使用的是基本接口,从GridManager类中继承该基本接口要求我强制转换以获得对其他属性的访问权限。

So I'm trying to work out a clean solution without the casting. 因此,我试图在不进行强制转换的情况下制定出一个干净的解决方案。

I've searched many examples online and cant quite get the answer I'm looking for, so looking for any advice really. 我在网上搜索了许多示例,但无法完全找到所需的答案,因此,确实需要任何建议。

Many thanks. 非常感谢。

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

UPDATE Ok, so my primary goal is to have more than one GridManager from which other objects have common functionality, so my thought was to use base interfaces to achieve this. 更新好的,所以我的主要目标是拥有一个以上的GridManager,其他对象具有该GridManager的共同功能,因此我的想法是使用基本接口来实现这一目标。

From the GridManager the SelectedTarget (ITargetObjectBase) object will have common logic, which is fine, but unique logic also at the GridManager. 从GridManager中,SelectedTarget(ITargetObjectBase)对象将具有通用逻辑,这很好,但是在GridManager中也具有唯一逻辑。

I did think about going the route suggested by Prasanna prior to me asking the question, should have mentioned that, kinda why I left the IVehicleObjectBase commented in, but I'm not sure what guidelines there are for the creating several generic definitions. 在问这个问题之前,我确实考虑过Prasanna建议的路线,应该提到这一点,这就是为什么我在IVehicleObjectBase中添加了注释,但是我不确定用于创建几个通用定义的指导原则。

I've added some additional code with concrete classes tho hopefully give a better idea what I'm on about. 我在具体的类中添加了一些其他代码,希望可以更好地了解我所从事的工作。

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

So I think my best two options are either to go the generic definition route or to remove the ITargetObjectBase property from GridManagerBase and just have ITargetObject within an IGridManager interface. 因此,我认为我最好的两个选择要么是走通用定义路线,要么是从GridManagerBase删除ITargetObjectBase属性,而在IGridManager接口中只有ITargetObject。

  • The reason that a cast is not needed for GridTarget is that: it is of type IGridPoint which directly contains the definition for HasVehicle . GridTarget不需要GridTarget类型IGridPoint的原因是:它是IGridPoint类型,直接包含HasVehicle的定义。
  • Whereas, SelectedTarget is of type ITargetObjectBase . SelectedTarget的类型为ITargetObjectBase ITargetObjectBase does not directly contain the definition for SomeValue . ITargetObjectBase不直接包含了定义SomeValue So a cast to ITargetObject is needed. 因此,需要ITargetObjectITargetObject
  • But a cast is not required in SelectedTarget.Row as ITargetObjectBase contains definition for Row . 但是,在SelectedTarget.RowITargetObjectBase ,因为ITargetObjectBase包含Row定义。

In your case, you could make IGridManagerBase into a type with two generic parameters, as shown below. 在您的情况下,可以将IGridManagerBase为具有两个通用参数的类型,如下所示。 Then you could call SelectedTarget.SomeValue without a cast 然后您可以在不进行强制转换的情况下调用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; }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM