当您拥有抽象类型的数组时,如何访问不在抽象类型上的派生类型成员

时间:2018-01-26 19:05:42

标签: c# unity3d

请查看以下代码块,以提供符合正确背景的问题。

抽象类

public abstract class Asset
{
    public GameObject Mode { get; set; }
    public AssetDimensions Dimensions { get; set; }
    public string BundleName { get; set; }
    public string ModelName { get; set; }
    public virtual string Type { get; }

    public string Sku
    {
        get
        {
            return this._sku;
        }
    }

    private string _sku;

    public Asset(AssetConfig assetConfig)
    {
        this.Model = null;
        this.Dimensions = new AssetDimensions(assetConfig.dimensions);
        this.BundleName = assetConfig.bundleName;
        this.ModelName = assetConfig.modelName;

        this._sku = assetConfig.sku;
    }
}

派生类

public class SpecificAsset : Asset
{
    public SpecificAssetController Controller { get; set; }
    public override string Type
    {
        get
        {
            return this._type;
        }
    }

    private string _type;

    public SpecificAsset(AssetConfig assetConfig) : base(assetConfig)
    {
        this._type = "SpecificAsset";
    }
}

初始化列表< Asset>并向其添加SpecificAsset

public List<Asset> Assets = new List<Asset>();

Assets.Add(new SpecificAsset(assetConfig));

现在因为列表&lt; Asset&gt;声明我尝试访问Asset does not contain a definition for Controller

时收到Assets[0].Controller

在C#中获得这种动态功能的惯用方法是什么?我需要能够在集合中存储不同的特定类型,并对其非派生成员进行操作。我是新鲜的JavaScript土地,狗可以是猫,所以任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:3)

简单的强制转换可能很有用,但对许多应用程序都没有用。我建议一起采取不同的方法。如何使用泛型让实现类处理属性类型(并将属性保留在基类中供所有人使用)。

public abstract class Asset<T>  where T : IController
{
    ...
    public T Controller { get; set; }
    ...
}
public interface IController
{
    void ContollerMethod();
}

实现看起来像这样:

public class SpecificAsset : Asset<ControllerImpl>
{
    ....
}
public class ControllerImpl : IController 
{
    public void ControllerMethod()
    {
        //Some code here...
    }
}

当您需要在基类中拥有一个或两个不同类型的属性时,此方法可以很好地工作。这允许类继承来定义它们将使用的类型。这不是每次都很好的方法(例如,如果你想让实现类定义3种以上的不同类型)。

编辑:我还会注意到这会使事情变得更容易的情况。请考虑以下代码:

public void TestMethod()
{
    List<Asset<IController>> assets = new List<Asset<IController>>();
    //Populate assets list here
    foreach (Asset<IController> asset in assets)
    {
        asset.Controller.ControllerMethod();
        //Here we cannot cast to a specific type easily because we may not know them at runtime. 
        //With the generic, we can still make any appropriate calls and not know the specifics
    }
}

答案 1 :(得分:0)

试试((SpecificAsset)Assets[0]).Controller。理想情况下,你会使用is and as casts以便获得某种安全性,但如果你确定它们总是来自Asset,那么硬拼接就可以了。

您应该调查abstact classes,您可以创建一个BaseAsset类,其中包含所有Asset的公共属性,AssetSpecificAsset也只会必须实现特定于它们的属性。至于列表的输入,它可以保持不变。