2012-10-20 45 views
3

我有情况下,我给了一个对象的集合,这些对象都来自同一个基类。如果我遍历集合并检查每个项目的类型,我可以看到该对象是派​​生类型,然后相应地处理它。我想知道的是,除了我已经在做的事之外,是否还有更简单的方法来执行派生类型的检查。代码重复通常不是必需的,所以我目前的方法对我来说似乎有点偏离。可以在没有为基类类型的每个派生类类型进行类型转换的情况下再次降级上传的对象?

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 
} 

目标是我们可以根据需要返回尽可能多的不同类型的消息给客户端。每个Web服务调用都不会收到单个消息,被调用者可以在单次旅程中了解其所有错误/成功信息,并从消息中消除字符串解析特定信息。

我最初虽然关于使用泛型,但由于Web服务可能具有不同的消息类型,因此集合被扩展为使用基类消息类。

+0

你究竟在努力实现什么?我问的原因是,你的方式闻起来像一个反模式。当你不得不用这种方式施展时,这通常是一个不好的迹象。查看Liskov替换原则(http://en.wikipedia.org/wiki/Liskov_substitution_principle) –

+1

我编辑了这个问题来解释我的总体目标。 – JWilliams

回答

4

它可能会移动到DoSomethingA有每个子类提供自己的实现:

public abstract class A 
{ 
    abstract void DoSomething(); 
} 

void Iterate() 
{ 
    Foo f = new Foo(); 
    foreach(A item in f.Collection) 
    { 
     item.DoSomething(); 
    } 
} 
0
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在类中真的没有任何内容。

1

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

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

所以MyClass<T>只需要某种类型,executeCode将有一个想法是什么方法都暴露出什么操作可以在传递的对象的数据来进行。 这可以避免需要投射,因为您正在指定必须遵循的合约。

0

李是正确的。只要让项目决定,该怎么做。它知道这是最好的类型,因此知道该怎么做。你甚至可以给一些标准的实现,如果它与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的建议,尽管接口和抽象基类在后台有些不同。

我通常更喜欢上面的那个,因为我通常倾向于给基类提供一些标准的行为,并且只在实现派生类时才会实现派生类。

相关问题