如何在不强制转换的情况下引用具有不同类型的父变量

本文关键字:同类型 变量 引用 情况下 转换 | 更新日期: 2023-09-27 18:31:18

我有这种情况

public class Base
{
    public Basedef def;
}
public class A : Base
{
}
public class B : A
{
    public int GetBar()
    {
        return def.bar;
    }
}

public class BaseDef
{
}
public class ADef : BaseDef
{
    public int foo;
}
public class BDef : ADef
{
    public int bar;
}

如您所见,方法 B:GetBar() 中存在错误,因为 def 无法访问 bar,但是如果您使...

public int GetBar()
{
    return (def as BDef).bar;
}

应该可以工作,但我想避免强制转换,如何在不使用强制转换的情况下使用基类中创建的引用从定义中获取属性?

为什么要避免强制转换?,因为容易出现运行时错误并且更容易引入错误,我想要类型安全的编码。

我想做什么

public class Factory
{
    public static Base<BaseDef> Create(BaseDef d)
    {
        if(d is BDef)
            return new B(); //Error, can not convert B to Base<BaseDef>
    }
}
public class Program
{
    B instance = Factory.Create(new BDef()); //Error, can not convert to Base<BaseDef> to B
}

我正在寻找一个优雅的解决方案

再见!

如何在不强制转换的情况下引用具有不同类型的父变量

要获得优雅的、无强制转换的解决方案,编译器需要知道defGetBar() 中的BDef。这是一种方法,我认为这种方法非常适合您的情况:

public class Base<T> where T : BaseDef
{
    public T def { get; set; }
}
public class A<T> : Base<T> where T : ADef
{
    public int GetFoo()
    {
        return def.foo; // this works, too
    }
}
public class B : A<BDef>
{
    public int GetBar()
    {
        return def.bar;
    }
}

(顺便说一下,您应该使用公共属性,而不是公共字段。老实说,公共变量和公共属性访问器有什么区别?出于某些原因。

更新:您的Factory方法可能类似于以下方法之一:

public static Base<T> Create<T>(T d) where T : BaseDef
{
    if(typeof(T) == typeof(BDef))
        return (Base<T>)(object)new B();
    else
        return null;
}
public static T Create<T, U>(U d) where T : Base<U> where U : BaseDef
{
    T result;
    if (typeof(T) == typeof(B))
        result = (T)(object)new B();
    else
        throw new NotImplementedException();
    result.def = d;
    return result;
}
public static T CreateAlternate<T, U>(U d) where T : Base<U>, new() where U : BaseDef
{
    return new T { def = d };
}

用于:

void Main()
{
    Factory.Create(new BDef());
    Factory.Create<B, BDef>(new BDef());
    Factory.CreateAlternate<B, BDef>(new BDef());
}

我喜欢最后一个,因为没有强制转换,只要new()约束不是问题,或者第一个如果简洁的调用代码非常有价值(因为可以推断泛型类型)。

使用强制转换执行此操作不是类型安全的,因为您要执行的操作从根本上说不是类型安全的。

您有一个类 A 和一个类 B 是 Base 的子类,并且 Base 具有对 BaseDeF 的引用。BaseDef可以是ADef或BDef,你不知道是哪一个,当然不是从告诉B的任何东西中。

但是,如果您使用泛型,则可以向 B 提供它所需的信息,以了解其 BaseDef 引用实际上是一个 BDef。

public class Base<T> where T : BaseDef
{
    public T def;
}
public class A<T> : Base<T> where T : ADef
{
}
public class B : A<BDef>
{
    public int GetBar()
    {
        return def.bar;
    }
}

为什么要避免强制转换?,因为容易出现运行时错误并且更容易引入错误,我想要类型安全的编码。

我不明白为什么铸造容易出错,如果你不知道defRuntimeType是什么,我会说你的设计是错误的。

在我看来,您应该知道它的运行时类型是什么。

有解决方法

解决方法 1:

public int GetBar()
{
    if (def is BDef)
        return ((BDef)def).bar;
    return 0;//some default value
}

解决方法 2:介绍一个enumwho am I

public enum DefType
{
    BaseDef = 0,
    ADef =1,
    BDef =2
}
public class BaseDef
{
    public virtual DefType MyType
    {   
        get{ return  DefType.BaseDef; }
    }
}
public class ADef
{
    public override DefType MyType
    {   
        get{ return  DefType.ADef; }
    }
}

然后像使用它一样

switch(def.MyType)
{
    case DefType.ADef:
    {
        (ADef).foo;//you know who is this here right?
    }
    ...
}

使 Basedef 成为一个 abstact 类并禁止在其上添加抽象属性是否有意义?