Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

friendly classes in c#

actually i refactor some portion of code. what i want to do is to initialize an object "Task" with an object "TaskArgument". let s say "TaskArgument" is abstract and "Task" implements a method "OnEnterTask(TaskArgument args)" and is sealed (for some special behavior of the existing system, which is out of scope).

old code:

public sealed class Task : SomeSystemBaseTask {
  private int accessMe; 
  private int meToo;

  public void OnEnterTask(TaskArgument args) {
    if (args is SimpleTaskArgument) {
      accessMe = ((SimpleTaskArgument)args).uGotIt;
      meeToo = 0;
    } else if (args is ComplexTaskArgument) {
      accessMe = ((ComplexTaskArgument)args).uGotItValue * ((ComplexTaskArgument)args).multiplier;
      meToo = ((ComplexTaskArgument)args).multiplier - 1;
    }
  }
}

what would be the best practise avoid the typecheck? my first stupud thought was:

public abstract class TaskArgument {
    internal public abstract Initialize(Task args);
}

public class SimpleTaskArgument : TaskArgument {
    public int uGotIt = 10;

    internal public Initialize(Task task){
        task.accessMe = uGotIt;
    }
}

public class ComplexTaskArgument : TaskArgument {
    public int uGotItValue = 10;
    public int multiplier = 10;

    internal public Initialize(Task task){
        task.accessMe = uGotItValue*multiplier;
        task.meToo = multiplier - 1;
    }
}

public sealed class Task : SomeSystemBaseTask {
    public int accessMe;
    public int meToo;

    public void OnEnterTask(TaskArgument args){
        args.Initialize(this);
    }
}

but then my "accessMe" is public and the "Initialize" method works only with "Task". so i moved the typechecking to another place (in future). is there any best practise or good design idea.

..."internal public"... mmhhmm?

another crazy idea was an inner class, but i dont like those and it make such a simple case more complex or don't:

public abstract class TaskArgument {
    internal public abstract Initialize(ITaskWrapper wrapper);
}

public class SimpleTaskArgument : TaskArgument {
    ...
}

public class ComplexTaskArgument : TaskArgument {
    ...
}

public interface ITaskWrapper {
    public int AccessIt { set; get; } 
    ...  
}

public sealed class Task : SomeSystemBaseTask {
    private int accessMe;
    ...

    class TaskWrapper : ITaskWrapper {
        ...
    }

    public void OnEnterTask(TaskArgument args){
        args.Initialize(new TaskWrapper(this));
    }
}

where is the best place for initialization when it is based on the given Type of the "TaskArgument"?

kindly excuse my bad english knowledge

greetings mo

like image 876
mo. Avatar asked Dec 09 '22 17:12

mo.


1 Answers

Use an interface.

public void OnEnterTask(TaskArgument args) { 
   if (args is SimpleTaskArgument) { 
      accessMe = ((SimpleTaskArgument)args).uGotIt; 
   } else if (args is ComplexTaskArgument) { 
      accessMe = ((ComplexTaskArgument)args).uGotItValue * ((ComplexTaskArgument)args).multiplier; 
   } 
} 

becomes

public void OnEnterTask(ITaskArgument args) { 
   accessMe = args.GetAccessMe();
} 

Then you have your classes implement ITaskArgument and implement the method for each class. In general, when you're doing something like this:

accessMe = ((ComplexTaskArgument)args).uGotItValue * ((ComplexTaskArgument)args).multiplier;

where you're accessing multiple properties on an object to perform a calculation, it usually makes sense to push that logic into the class itself.

like image 112
reustmd Avatar answered Dec 20 '22 18:12

reustmd