Search code examples
c#structpropertiesmultiple-instancesinteraction

Making methods that interact with instances of their structs


We went through structs at class and we've been tasked with creating a method inside the struct that changes the fields of an instance compared with another. For example, changing one's name if the other is a manager.

struct Employee 
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string FullName
    {
        get => FirstName + LastName;
    }
    public int Age { get; set; }
    public string Role { get; set; }
    public double Salary { get; set; }
    public bool IsManager { get; set; }

    public static void EditInfo(ref Employee e1, ref Employee e2)
    {
        if (e1.IsManager)
        {
            Console.WriteLine($"Feel free to set {e2.FirstName}'s info: ");
            e2.FirstName = Console.ReadLine();
            e2.LastName = Console.ReadLine();
            Console.WriteLine($"From now on thy name is {e2.FullName}!");
        }
        else if (e2.IsManager)
        {
            Console.WriteLine($"Feel free to set {e1.FirstName}'s info: ");
            e1.FirstName = Console.ReadLine();
            e1.LastName = Console.ReadLine();
            Console.WriteLine($"From now on thy name is {e1.FullName}!");
        }
    }
}

Now, I have this gut feeling that my creation is terrible. I'm not sure about how to actually approach this at all, and it looks like a valuable lesson to learn for real business applications. I would appreciate every tip and trick that is necessary to make these methods, that interact with multiple instances of the struct, better.


Solution

  • Edit: Clarification

    First you should make the mutable properties private set;, the constructor accept initial state, and make EditInfo an instance method. This more or less treats each Employee like a database record with access control, creating a simpler relationship.

    public class Employee
    {
        public Employee(string firstName, string lastName, bool isManager, ...)
        {
            FirstName = firstName;
            LastName = lastName;
            IsManager = isManager;
            // remaining properties...
        }
    
        public string FirstName { get; private set; }
        public string LastName { get; private set; }
        public bool IsManager { get; private set; }
        // remaining properties...
    
        public void Edit(Employee requester)
        {
            if (requester.IsManager) {
                // query input from the user, make changes, and notify the user.
            } else {
                // notify the user that he doesn't have permission to edit this employee. 
            }
        }
    }
    

    Using it thus becomes:

    var manager = new Employee("Your", "Boss", isManager: true);
    var sheep = new Employee("John", "Doe", isManager: false);
    
    sheep.Edit(manager); // Essentially says "edit sheep using manager as permission".
    

    Secondly, unless your instructor forbade you from using class, you should make it a class and get rid of all the ref declarations. struct and ref are very useful in the right cirumstances, but unless you're aware of the tradeoffs and code rigorously, its too easy to introduce a bug that will be difficult to reason about considering your experience level.

    Classes don't automatically make copies or require the ref keyword. Structs on the other hand do make copies without ref, thus semantically requiring(but not enforcing) it at every call site that makes modifications to it. This has further implications which you may not be aware of. Consider properties. Properties cannot be passed with ref, only locals, fields, and array elements. Unfortunately that means it's currently impossible to pass a struct property by ref(though subject to change in a future C# version). This will likely bite you down the road.

    In summary, prefer classes in C# unless you have a good reason to use structs(i.e. GC performance, very special purpose types). Above all, aim for readability.