0

I am having a problem. Lets see an example: you got this interface which would be implemented by Employee.cs and Owener.cs:

public interface IEmployee
 {
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string Location { get; set; }
  }

 public class Employee: IEmployee
 {
     public string FirstName { get; set; }

    public string LastName { get; set; }

    public string Location { get; set; }
}

  public class Owner: IEmployee
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string Location { get; set; }

    public string Status{ get; set; } <--- //problem string
}

Now when we are using Dependency Injection and it returns the object of employee or manager, thats where i run into problem.

public class EmployeeCheck{

   private IEmployee empObj;

  public EmployeeCheck(IEmployee _em)
  {
     empObj=_em
  }

public void PrintCheck()
 {
   string str=_em.FirstName;
   string str2=(Owner)_emp.Status <--- //problem...how do I access it?? It can't be accessed cause 
                                       //IEMployee doesn't have status field!
  }

So basically if I use IEmployee as the interface , I can't access fields in new the Owner class, and if I do put them in interface, then Employee class which doesn't need to implement it, will be forced to implement something it doesn't need! And I do need IEmployee due to DI injection or other design pattern


OK, I can't use abstract class...so lets discuss more about the IStatus solution...so you are talking about writing code like this:

public interface IStatus:IEmployee
{
    public string Title { get; set; }
}

public class Owner: IEmployee, IStatus { public string FirstName { get; set; }

public string LastName { get; set; }

public string Location { get; set; }

public string Status{ get; set; } <--- //problem string

}

But how do I work it in Employee check class?

public class EmployeeCheck {

   private IEmployee empObj;

  public EmployeeCheck(IEmployee _em, IStatus)
  {
 empObj=_em
  }

}

3 Answers3

0

It depends on how you use or why you have to use dependency injection. I think that in these cases according to your example it is not so good to use it, since it is giving you complexity in something simple.

If you are going to perform an action with the Status value, you could segregate the interface by generating a new one. Like this. public interface IStatus { string Status { get; set; } } and then you implement this interface just in Owner and in your constructor EmployeeCheck you inject IStatus.

But if it is not necessary why not IEmployee you do it as an abstract class.

public abstract class Employee
{
    public string Name { get; set; }
    public string LastName { get; set; }
    public string Location { get; set; }
}

public class Owner : Employee
{
    public string Status { get; set; }
}

public class EmployeeCheck 
{
  public EmployeeCheck(Employee employee)
  {
   var owner = employee as Owner;
   var statuts= owner.Status;
  }
}
Diego rincon
  • 131
  • 3
0

The scenario that you're dealing with could be handled traditionally using IoC Containers like StructureMap or Unity by using something called Named Instances. These containers provide this kind of functionality out of the box.

The same can be achieved in .NET Core in multiple ways. One way is to use the extension method from IServiceCollection. The below snippet walks you through how this could be done in your scenario

// using Microsoft.Extensions.DependencyInjection
// Startup.cs - ConfigureServices()
services.AddTransient(serviceProvider =>
{
    Func<string, IMyClass> func = key =>
    {
        switch (key)
        {
            case "MyClass":
                return serviceProvider.GetService<MyClass>();
            case "MyClass1":
                return serviceProvider.GetService<MyClass2>();
            default:
                throw new KeyNotFoundException();
        }
    };
    return func;
});

//Register your services here as usual
services.AddTransient<IMyClass, MyClass>();
services.AddTransient<IMyClass, MyClass2>();

You are essentially creating a factory here that is going to give out the dependency of the type that you need based on the key. The following snippet of code shows how this can be done within your controller.

// ctor of your controller
public MyController(Func<string, IMyClass> injector)
{
    // key here could be 'MyClass' or 'MyClass2'
    IMyClass service = injector("<key>");
}

Below is the structure of sample classes I have considered for the above sample

// implementation 1
public class MyClass : IMyClass
{
}

// implementation 2
public class MyClass2 : IMyClass
{
}

// interface
public interface IMyClass
{
}

There are also other ways to handle this. You can take a look at this answer for other approaches.

Sai Gummaluri
  • 1,340
  • 9
  • 16
0

The first question you need to consider is: what is EmployeeCheck supposed to do when it is instantiated with an Employee (say) since it seems to require Status to print a check?

The whole idea behind interfaces is that they provide a contract for the operations that can be performed with an object. In this case, you are trying to do something (use Status) that is not specified in the contract so the type system is making it a little bit harder (forcing you to cast).

An option (as suggested by @Diegorincon) which avoids casting, is to create another interface (something like IHasStatus) which implements IEmployee and then change the type in EmployeeCheck (CheckPrinter maybe clearer?) to IEmployeeWithStatus.

interface IEmployee
{
     string FirstName { get; }
     string LastName { get; }
    
}
interface IEmployeeWithStatus:IEmployee
{
    string Status { get; }
}
public class Owner : IEmployeeWithStatus
{
    public string FirstName { get; }
    public string LastName { get; }
    public string Status { get; }
}
class EmployeeCheck
{
    private readonly IEmployeeWithStatus _employeeWithStatus;
    public EmployeeCheck(IEmployeeWithStatus employeeWithStatus)
    {
        _employeeWithStatus = employeeWithStatus;
    }

    void PrintCheck()
    {
        // no casting needed
        Console.Write($"{_employeeWithStatus.FirstName} {_employeeWithStatus.LastName} {_employeeWithStatus.Status}");
    }
}

If you are stuck using the signatures in your example, one option for writing the code is to write a switch statement using the type pattern:

   switch (employee)
     {
           case Owner owner:
           {
               // you can use owner.Status here
               Console.WriteLine(owner.Status);
           }
           break;
           case Employee employee:
           {
               // hmm.., now what?!
           }
           break;
     }

It's cleaner than having to cast all over the place but at the end of the day, it's just pushing the same problem around.

(In the Object Oriented paradigm, this situation comes up all the time where you have a object in hand with a more general type (something like Animal) but you find yourself wanting to do operations based on its specific type (something like Dog). Switching on type as the code above does is usually considered a code smell. With more details, I might be able to offer some other ideas)

user1239961
  • 36
  • 1
  • 3