可以再次对基础类型的每种派生类类型进行铸造,可以再次降低一个上casted的对象



我有一个情况,即给出了所有从同一基类得出的对象的集合。如果我迭代集合并检查每个项目的类型,我可以看到该对象是派生类型的,然后相应地处理。我想知道的是,除了我已经在做什么外,还有一种更简单的方法来执行派生类型的检查。通常不需要代码重复,所以我当前的方法对我来说似乎有点不合时宜。

class A {}
class B : A {}
class C : A {}
class D : C {}
class Foo
{
    public List<A> Collection { get; set; }
}
class Bar
{
    void Iterate()
    {
        Foo f = new Foo();
        foreach(A item in f.Collection)
        {
            DoSomething(a);
        }
    }
    void DoSomething(A a)
    {
        ...
        B b = a as B;
        if(b != null)
        {
            DoSomething(b);
            return;
        }
        C c = a as C;
        if(c != null)
        {
            DoSomething(c);
            return;
        }
        D d = a as D;
        if(d != null)
        {
            DoSomething(d);
            return;
        }
    };
    void DoSomething(B a){};
    void DoSomething(C a){};
    void DoSomething(D a){};
}

我正在使用一个Web服务,每个Web服务都必须具有相同的结果类型。

class WebServiceResult
{
    public bool Success { get; set; }
    public List<Message> Messages { get; set; }
}
class Message
{
    public MessageType Severity { get; set; } // Info, Warning, Error
    public string Value { get; set; } //
}
class InvalidAuthorization: Message
{
    // Severity = MessageType.Error
    // Value = "Incorrect username." or "Incorrect password", etc.
}
class InvalidParameter: Message
{
    // ...
}
class ParameterRequired: InvalidParameter
{
    // Severity = MessageType.Error
    // Value = "Parameter required.", etc.
    public string ParameterName { get; set; } //
}
class CreatePerson: Message
{
    // Severity = MessageType.Info
    // Value = null
    public int PersonIdentifier { get; set; } // The id of the newly created person
}

目标是我们可以根据需要将尽可能多的不同类型的消息返回客户端。Callee无需收到单个消息,而是可以在一次旅行中知道他们的所有错误/成功,并消除字符串从消息中解析特定信息。

i最初是关于使用仿制药的,但是由于Web服务可能具有不同的消息类型,因此该集合被扩展以使用基本消息类。

可能可以将DoSomething移至A并让每个子类提供自己的实现:

public abstract class A
{
    abstract void DoSomething();
}
void Iterate()
{
    Foo f = new Foo();
    foreach(A item in f.Collection)
    {
        item.DoSomething();
    }
}

一个想法是在基类或接口上使用一般约束。

public class MyClass<T> where T : BaseClass, IInterface
{
   public void executeCode<T>(T param) {};
}

因此,MyClass<T>仅采用某种类型,executeCode将了解哪些方法已公开,并且可以对传递对象的数据执行哪些操作。这避免了铸造的需求,因为您指定了必须遵循的合同。

typeof(ParentClass).IsAssignableFrom(typeof(ChildClass));

返回true是可能的。

也可以这样:

typeof(ParentClass).IsAssignableFrom(myObject.GetType());

但是在您的示例中,您实际上调用了每种对象类型的方法。因此,无论如何您都需要演员,除非您不介意重构没有超负荷的收集。

如果要保持超负荷:

这样的东西
foreach(A item in f.Collection)
{
    Type itemType = item.GetType();
    if (typeof(B).IsAssignableFrom(itemType)
        DoSomethingB(item);
    else if (typeof(C).IsAssignableFrom(itemType)
        DoSomethingC(item);
    //...
}

编辑:我喜欢更多李的答案。将虚拟/覆盖函数添加到类类型将是一个更好的设计,并且更易于处理,除非dosomething在类中确实没有什么可做的。

Lee是正确的。只需让项目决定该怎么办。它知道它是最好的,因此知道该怎么做。您甚至可以通过不抽象而是虚拟的,甚至可以提供一些标准的实现,如果它与A中的实现相同。但是请注意,编译器不会要求实施。

public class A 
{
  public virtual DoSomething(){"What A needs doning!"}
}
public class B : A
{
  public override DoSomething() {"What B needs doing!"}
}

另一种方法是使用接口。

public interface IAinterface 
{
  void DoSomething();
}
public class A : IAinterface
{
  void DoSomething(){...}
}
public class B : IAinterface
{
  void DoSomething(){...}
}

这更像是Lees的建议,尽管接口和抽象基类在背景中的作用有所不同。

我通常更喜欢上层,因为我通常倾向于给基类一些标准的行为,并且仅在有不同的东西时才能实现派生的类。

相关内容

  • 没有找到相关文章

最新更新