Click here to Skip to main content
14,934,895 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,
I was wondering if any one could help. I'm writing an application and wanted to check if I am using interfaces correctly.

I have an interface which contains a number of properties.

C#
public interface Detail {
  string Name {get;set;}
  int Age {get;set;}
}


I have two other classes that implement this interface which then contains there own unique properties.

I have another interface:
C#
public interface UserManager {
   void CreateUser(Detail user);
}

When I come to implement CreateUser, do i need to cast ie

C#
public void CreateUser(Detail user){
TestClass1 = user as TestClass1;
Console.Write(user.Name + " " + user.Age + " "+  user.TestClass1Property);
}


C#
public void CreateUser(Detail user){
TestClass2 = user as TestClass2;
Console.Write(user.Name + " " + user.Age + " "+  user.TestClass2Property);
}


Is this the correct approach?

What I have tried:

I have tried the above and it appears to work ok, I just want to check is this good practice the way I have done this?
Posted
Updated 4-Apr-16 4:07am
Comments
   
Totally bad approach. Right idea is: create a class/struct instance, assign to interface variable/member, and work with interface only, never casting it to implementing class/struct.
—SA
Member 4336594 5-Apr-16 3:12am
   
Thanks. Would you be able to give an example please?
   
MyImplementation = class (IMyInterface) {/* ... */}
// ...
IMyInterface obj = new MyImplementation() // not MyImplementation obj = ...
obj.DoSomething();

You should follow the naming convention for interfaces and prefix them with an "I": IDetail, etc.

You shouldn't use the as-cast. Or better: Your class/interface design shouldn't require it. If it does require it then the whole point of interfaces is lost on your class design: Interfaces serve the purpose of loose coupling between classes, your cast re-introduces strong coupling with the added trapdoor of potentially failing.
   
Comments
   
5ed, but perhaps it needs some explanation. If an inquirer makes such a native design mistake, this person doesn't understand some background and hence may not understand your reasons.
—SA
F-ES Sitecore is right...but also wrong, a little.
You can't use this code:
C#
public void CreateUser(Detail user){
    TestClass1 = user as TestClass1;
    Console.Write(user.Name + " " + user.Age + " "+  user.TestClass1Property);
    }
Because TestClass1Property is not a member of the Detail Interface, and since the object you pass in must be a member of Detail, but doesn't have to be a member of TestClass1, you can't access any TestClass1 specific fields, properties, event, or methods via the user variable. And you will get a compilation error if you try.
What you would need to do is:
C#
       public interface IDetail
            {
            string Name { get; set; }
            int Age { get; set; }
            }
        public class TestClass1 : IDetail
            {
            public int TestClass1Property { get; set; }
            }
...
        public void CreateUser(IDetail user)
            {
            TestClass1 tc = user as TestClass1;
            if (tc != null)
                {
                Console.Write(user.Name + " " + user.Age + " " + tc.TestClass1Property);
                }
            }
Or
C#
...
                Console.Write(tc.Name + " " + tc.Age + " " + tc.TestClass1Property);
...
   
Comments
Member 4336594 4-Apr-16 10:15am
   
F-ES Sitecore mentions that its not good OOP, if this is the case. What would be the correct way of doing this?
OriginalGriff 4-Apr-16 11:04am
   
The correct way would be to have a method that accepts a TestClass1 instance instead of a IDetail instance.
If that means you need to have TestClass2 versions as well, then I'd probably use an abstract base class which forces the derived class to write a CreateUser method which returns the string you write to the console.
Then it's just a case of

Console.WriteLine(myInstance.CreateUser());

and the system will sort out which CreateUser method to call.
C#
public void CreateUser(Detail user){
TestClass1 = user as TestClass1;
Console.Write(user.Name + " " + user.Age + " "+  user.TestClass1Property);
}


The above code means that the method allows any class that implements Detail to be passed to the function, however your "as" means that while any class that implements Details can be passed in, if it isn't TestClass1 then the "as" will evaluate to null. So, no, you should do any casting or use "as".

C#
public void CreateUser(Detail user){
Console.Write(user.Name + " " + user.Age + " "+  user.TestClass1Property);
}


Edit: The above code is rubbish, I didn't see you were trying to access TestClass1Property off of user so ignore it.

Also you should prefix your interfaces with "I" so "IDetail" rather than "Detail". It is proper convention and makes it obvious when you're dealing with an interface and not a concrete class.
   
v2
Comments
Member 4336594 4-Apr-16 10:04am
   
Thanks, so when I do :
public void CreateUser(Detail user){
Console.Write(user.Name + " " + user.Age + " "+ user.TestClass1Property);
}
user.TestClass1Property will not exist
F-ES Sitecore 4-Apr-16 10:09am
   
Ah ok, in that case you're kinda breaking good OOP. If you need to access TestClass1Property then make the function accept TestClass1 rather than IDetail.

You *can* do this, but you shouldn't.

TestClass1 tc = user as TestClass1;
Console.WriteLine(user.Age); // you know this is valid as user is IDetail
if (tc != null)
{
// here we check to see if the "as" returned null
Console.WriteLine(tc.TestClassProperty);
}

So with the above you can still pass anything that implements IDetail, however if that object is of type TestClass then you can execute code specific to that class. As I said, you can do this but you shouldn't.
OriginalGriff 4-Apr-16 10:08am
   
Not quite - you'll get a compilation error since TestClass1Property isn't a member of the IDetail interface.
F-ES Sitecore 4-Apr-16 10:13am
   
Yeah I was copying and pasting without really looking :o
OriginalGriff 4-Apr-16 10:56am
   
:laugh:
We've done it!
Member 4336594 4-Apr-16 10:33am
   
If this is breaking OOP, what would be the best way to accomplish this? Thanks
F-ES Sitecore 4-Apr-16 10:43am
   
Ideally split it into two functions, one that deals with the IDetail things, and one that deals with the TextClass1 things. Or you could look to use something like a "factory patten" and have different implementations for different objects that implement IDetail and the factory will return the correct class with the relevant function that handles TestClass1, TestClass2 or whatever other classes might implement IDetail, it all depends on the architecture of what you're doing and what you're looking to achieve in the bigger picture.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900