26

I have the following interfaces defined:

public interface IAudit {
    DateTime DateCreated { get; set; }
}

public interface IAuditable {
    IAudit Audit { get; set; }
}

The IAuditable interface says which classes I will have an Audit for. The IAudit interface is the actual Audit for that class. For example say I have the following implementations:

public class User : IAuditable {
    public string UserName { get; set; }
    public UserAudit Audit { get; set; }
}

public class UserAudit : IAudit {
    public string UserName { get; set; }
    public DateTime DateCreated { get; set; }

    public UserAdit(User user) {
        UserName = user.UserName;
    }
}

Now given an object which is IAuditable (User from above), I'd like to be able to create an intance of IAudit (UserAdit from above) by feeding in the IAuditable object into the constructor. Ideally i'd have something like:

if (myObject is IAuditable) {
    var audit = new IAudit(myObject) { DateCreated = DateTime.UtcNow }; // This would create a UserAudit using the above example
}

However I have a bunch of problems:

  • You can't create an instance of an interface
  • No where in the code does it define which IAudit applies to which IAuditable
  • I can't specify that the IAudit interface must have a constructor which takes an IAuditable

I'm sure this is a design pattern many have had before but I can't get my head around it. I'd really appreciate if someone could show me how this can be achieved.

nfplee
  • 7,643
  • 12
  • 63
  • 124

6 Answers6

19

You can't create an instance of an interface

Correct. You create an instance of an object implementing an interface:

IAuditable myUser = new User();

No where in the code does it define which IAudit applies to which IAuditable

You can't do this directly with just one interface. You will need to rethink your design.

You can use a open generic type in the interface and implement it with closed types:

public interface IAudit<T> {
    DateTime DateCreated { get; set; }
}

public class UserAudit : IAudit<User> {
    public string UserName { get; set; }
    public DateTime DateCreated { get; set; }

    public UserAdit(User user) {
        UserName = user.UserName;
    }
}

I can't specify that the IAudit interface must have a constructor which takes an IAuditable

Correct, you can't. See here. You need to create such a constructor on the implementers.

Community
  • 1
  • 1
Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • Useful answer, useful info for OP, but still focuses too much on the c#/.net specifics to get an upvote from me ... for now. Tridus' addresses the _real_ issue IMO. Still, useful info for OP. – Marijn Aug 19 '11 at 13:44
  • Hi cheers, i've accepted @Tridus answer but i have used parts of your suggestion to help. – nfplee Aug 19 '11 at 15:02
  • Why would we do it that way instead of creating it like User user = new User()? What is the benefit of declaring it like IAuditable myUser = new User()? – Berke Kaan Cetinkaya Oct 21 '22 at 06:22
18

No where in the code does it define which IAudit applies to which IAuditable I can't specify that the IAudit interface must have a constructor which takes an IAuditable

You could fix these two by adding a CreateAudit() function to your IAuditable. Then you'd get an IAudit created from the IAuditable. As a bonus if you wanted to store a reference to the IAudit in the IAuditable (or vice-versa) so you can have them related to each other, it's pretty easy to have an implementing class do that. You could also add GetAuditable() to IAudit to get the IAuditable it was created from, for example.

Simple implementation would look like this (on a class implementing IAuditable):

public IAudit CreateAudit()
{
    UserAudit u = new UserAudit(UserName);
    return u;
}
Tridus
  • 5,021
  • 1
  • 19
  • 19
  • 2
    +1 Exactly the answer I was about to post, but you appeared to `really` understand the question sooner. – Marijn Aug 19 '11 at 13:39
  • @nfplee: you're really asking more of a design question, and the answer you're after does not lie in c# / .net specifics. This is your answer, or at least puts you in the right direction. – Marijn Aug 19 '11 at 13:40
  • @Tridus: Thanks for your answer but it's late on a Friday afternoon and clearly my brain has fried lol. If i try to say ((IAuditable)myObject).CreateAudit(). It can't find the CreateAudit method. I believe i've done everything you have stated. – nfplee Aug 19 '11 at 14:53
  • @Tridus: Please ignore me, i should really learn to build more and rely less on intellisense lol. Thanks again for your help. – nfplee Aug 19 '11 at 15:02
6

Obviously you cannot create an instance of an interface, but if you were really trying to create an instance of the passed in class you could do this:

IAuditable j = ((IAuditable)Activator.CreateInstance(myObject.GetType()));

You need to know which concrete class to construct and in your example the only option is myObject.

Alternatively you could research something called 'Dependancy Injection' which allows you to specify which type of concrete class to "inject" into parameters that call out interfaces in constructors, or in fields. I'm not sure your total design, so this might be applicable. In Dependancy Injection you can state in your code IAuditables should be created using UserAudit, although there's a little more wireup than simply calling "new IAuditable"

deepee1
  • 12,878
  • 4
  • 30
  • 43
5

One way would be using generics.

Once you've a T type which implements I interface and has a public, parameterless constructor, you can create an instance of T:

public void Create<T>() where T : IAudit, new()
{
     T instance = new T();
     // TODO: Your logic here to use T instance of IAudit
} 

I don't know your code architecture or goal, but you can create a factory method like one above to create instances of IAudit objects.

Furkan Öztürk
  • 1,178
  • 11
  • 24
Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
0

If you are in need to create Instance for an Interface,You can create a public class named FactoryClass() which contains all the Interfaces method. you can use the following code:

public class FactoryClass  //FactoryClass with Interface named "IINterface2"
{
   public IInterface2 sample_display()   //sample_display() is a instance method for Interface
   {
       IInterface2 inter_object = null;   //assigning NULL for the interface object
       inter_object = new Class1();       //initialising the interface object to the class1()
       return inter_object;   //returning the interface object
   }
}

In Main() Class add the following code :

IInterface2 newinter; //creating object for interface in class main()
FactoryClass factoryobj=new FactoryClass();  // creating object for factoryclass

In constructor add the following :

newinter=factoryobj.sample_display() // initialisingg the interface object with the instance method of factoryobj of FACTORY CLASS.

you can call the ffunction by using the following code :

newinter.display() //display() is the method in the interface.
Elango
  • 53
  • 2
  • 12
0

You can create a static Interface variable outside of the scope and then use it in the code.

static IRequestValidator ir;


static void Main(string[] args)...
user890332
  • 1,315
  • 15
  • 15