Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

274
Views
Convert abstract type to 7 possible other types

I have the following abstract class:

public abstract partial class AsyncResult
{
}

And 7 other classes that inherit from it(here are only 2 for reference):

public partial class AsyncSearchResult : AsyncResult
{
    private SearchResult searchResultField;
    
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Namespace="urn:core_2020_2.platform.webservices.netsuite.com", Order=0)]
    public SearchResult searchResult
    {
        get
        {
            return this.searchResultField;
        }
        set
        {
            this.searchResultField = value;
        }
    }
}

public partial class AsyncGetListResult : AsyncResult
{
    private ReadResponseList readResponseListField;
    
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order=0)]
    public ReadResponseList readResponseList
    {
        get
        {
            return this.readResponseListField;
        }
        set
        {
            this.readResponseListField = value;
        }
    }
}

I have a method that returns the abstract type and I need to cast it to one of the specific types in order to access the desired property.

I can't find a way to cast it at compile time without writing 7 ifs for each case and duplicate the code a lot.

Appreciate any kind of help.

over 4 years ago · Santiago Trujillo
2 answers
Answer question

0

I like using the visitor pattern for this:

public interface IAsyncResultVisitor
{
    void Accept(AsyncSearchResult searchResult);
    void Accept(AsyncGetListResult getListResult);
    // Etc...
}

public abstract partial class AsyncResult
{
    public abstract void Visit(IAsyncResultVisitor visitor);
}

public partial class AsyncSearchResult : AsyncResult
{
    // ...
    public override void Visit(IAsyncResultVisitor visitor) => visitor.Accept(this);
}

Then:

public class AsyncResultProcessor : IAsyncResultVisitor
{
    public void ProcessAsyncResult(AsyncResult asyncResult)
    {
        asyncResult.Visit(this);
    }

    public void Accept(AsyncSearchResult searchResult)
    {
        // Access strongly-typed members of searchResult
    }

    public void Accept(AsyncGetListResult getListResult)
    {
        // Access strongly-typed members of getListResult
    }
}

Note that switch statements and switch expressions also help here, although they don't ensure that you've covered every single case (as the visitor pattern does):

switch (asyncResult)
{
    case AsyncSearchResult searchResult:
        // ...
        break;
}
over 4 years ago · Santiago Trujillo Report

0

I would've implemented visitor in different way. Problem with @canton7 implementation is that data have to know how people should work with it, but it's just plain data!

First: AsyncResult should have private protected constructor, so no other assemblies could "implement" this abstract class

public abstract class AsyncResult
{
    private protected AsyncResult() {}
}

public sealed class ResultOne : AsyncResult()
{
    public string Data { get; set; }
}
// 6 more to go

Make interface to match all types

public interface IAsyncResultVisitor
{
    void Visit(AsyncResult result);
    void VisitResultOne(ResultOne result);
    void VisitResultTwo(ResultTwo result);
    // 5 more to go
}

And create default visitor that's gonna have properties for each type containing visit strategy

public sealed class LambdaAsyncResultVisitor : IAsyncResultVisitor
{
    public Action<ResultOne> OnVisitOne { get; set; } 
    public void VisitResultOne(ResultOne result)
    {
       if (OnVisitOne is null)
           throw new InvalidOperationException("...");
       OnVisitOne.Invoke(result);
    }
    // 6 more to go
}

This would allow us to use it this way

AsyncResult result = ...;

string someString = "";
new LambdaAsyncResultVisitor
{
   OnVisitOne = r => someString = r.Data,
   OnVisitTwo = r => someString = "two",
   OnVisitThree => _ =>  throw new Exception("I know that is is impossible"),
}.Visit(result);

HandleSomeString(someString);

This gives much more flexibility than default visitor pattern

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!