【问题标题】:How to reference parent variable with a different type without casting?如何在不强制转换的情况下引用具有不同类型的父变量?
【发布时间】:2013-09-18 13:10:40
【问题描述】:

我有这种情况

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
}

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

再见!

【问题讨论】:

  • 我假设您希望 ADef 从 BaseDef 继承,但您没有编写它,因此将 BaseDef 转换为 BDef 毫无意义...
  • 为什么要避免演员表?如果没有虚拟方法或属性/反射,您想要实现的目标是不可能的
  • 假设您的意思是ADef : BaseDef,我已经编辑了您的问题。如果不编辑您的问题
  • Sriram,是的,我的意思是,感谢您指出这一点
  • Sriram,更新的问题,添加了为什么我想避免投射

标签: c# casting


【解决方案1】:

要获得一个优雅的、无强制转换的解决方案,编译器需要知道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;
    }
}

(顺便说一句,您应该使用公共属性,而不是公共字段。请参阅Honestly, what's the difference between public variable and public property accessor? 了解某些原因。)

更新:您的 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() constraint 不是问题,或者第一个如果简洁的调用代码非常有价值(因为可以推断出泛型)。

【讨论】:

  • 我想了想,A可以使用它的def引用获取foo值吗?
  • @JoeCabezas 是的,我的解决方案支持这一点,因为编译器知道defADef
  • 这给了我错误: Base b = new A(); (不能隐式转换类型A&lt;ADef&gt;' to Base')
  • Collection&lt;object&gt; c = new ObservableCollection&lt;string&gt;(); 无效的原因相同:它根本没有意义。你是如何尝试使用它的?您可能会受益于Base,它是Base&lt;T&gt; 的基类。如果您只需要将T 设为inout,则可以在通用接口上使用co/contravariance,但原样您有getset,这样就行不通了.
  • 在我的问题中添加了“我正在尝试做什么”,如果你有时间请检查一下
【解决方案2】:

使用演员表做这件事不是类型安全的,因为你试图做的基本上不是类型安全的。

您有一个类 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;
    }
}

【讨论】:

    【解决方案3】:

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

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

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

    有一些解决方法

    解决方法 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?
        }
        ...
    }
    

    【讨论】:

      【解决方案4】:

      将Basedef 设为抽象类并在其上添加抽象属性是否有意义?

      【讨论】:

      • 不,因为bar是B的一个特定属性,所以思路是使用Def类来创建A和B的实例
      • 另外,A 不应该使用自己的 def 访问 bar
      猜你喜欢
      • 1970-01-01
      • 2020-08-08
      • 2014-09-27
      • 2018-01-01
      • 2013-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-21
      相关资源
      最近更新 更多