Can I implement an interface in a C# in an .h file

2019-08-02 06:58发布

问题:

I have an interface that is used by several classes and the interface implementation is the same for all the classes. I would make it a base abstract class, but then it would stop the deriving classes from inhering from another class later on, which I need. So instead of reimplementing the same interface in all the classes, can I somehow implement the interface in one place, like an .h file and include the .h file in the cs file so the class "implements" the interface.

By the way, the interface consists mostly of properties and changed on delegates.

回答1:

I'm a little rusty on my C#, so there may certainly be a C#-specific way of doing this. However, in a more general sense, you could provide the implementation in its own, standard class file. For each class that needs to implement the interface, you would still need to declare the interface methods - but instead of having lengthy implementations copied-and-pasted into each, you could have one-line calls to the shared "include" implementation.

(This probably won't be the best solution, but should be a workable one that could at least get you started.)



回答2:

C# does not have a concept of header files. You can't do this easily in C#. If you implement an interface and you want to have the same implementation in another class then the other class needs to derive from the implementing class.

Example:

public interface IFoo
{
    void DoSomething();
}

public class SomeClass : IFoo
{
    public void DoSomething()
    {
    }
}

If you now want to have SomeOtherClass which has the same implementation as SomeClass then you need to derive SomeOtherClass from SomeClass or reimplement it or delegate the call to DoSomething to an instance of SomeClass. Another option would be to use a tool like DynamicProxy which can support mixin styles.



回答3:

EDIT: Scratch all below the line- as per the comments, that's probably not what you want.

Unfortunately mixins are not available as a built-in language feature in C#, other than through some questionable techniques, including post-compile tools like PostSharp. Some IoC tools can make mixin-like things happen also (see Best implementation of INotifyPropertyChange ever).

To @32bitkid's point, you can write extension methods. They are not interfaces, but they allow you to apply an implementation of a behavior to a type from outside that type. For instance, you can write:

public static class IPersonExtensions {
    // Note use of this keyword
    public static Int32 GetAge(this IPerson p) { return DateTime.Now - p.BirthDate; }
}

then use it thus:

var p = new Person( ... );
var pAge = p.GetAge();

Yes, that's how interfaces are normally used- though they get .cs files, not .h files. You can define the interface in it's own file, just like a class, and then declare the class as implementing the interface.

For example, in IFoo.cs:

public interface IFoo {
  public String Bar { get; set; }
}

and then in ConcreteFoo.cs:

public class ConcreteFoo : IFoo {
  // This property implements IFoo.Bar
  public String Bar { get; set; }
}

(This is an example of an auto-implemented property by the way)

IFoo doesn't even technically need to be in it's own file- it can be in any .cs file. By convention, it usually is in it's own though. Also, note the convention of using the I prefix for interfaces.

You might want to read more about this, here for example: http://www.csharp-station.com/Tutorials/Lesson13.aspx



回答4:

You basically need multiple inheritance which C# doesn't support, however you can still make use of an interface implementation in other classes that are already being derived from another class. One way I've come up with is using partial classes and T4 Text Templates. It's a slight hack but it's better than copy/pasting the same interface implementation in lots of derived classes. Below is a simplified example:

IInterface.cs

public interface IInterface
{
    void Foo();
}

InterfaceImpl.cs

public partial class InterfaceImpl : IInterface
{
    public void Foo()
    {
        Console.WriteLine("Foo");
    }
}

BaseClass.cs

using System;

public class BaseClass
{
    public void Bar()
    {
        Console.WriteLine("Bar");
    }
}

DerivedClassA.cs

public partial class DerivedClassA : BaseClass, IInterface
{
    public void FooBar()
    {
        this.Foo();
        this.Bar();
    }
}

DerivedClassAInterfaceImpl.tt

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<# var codeText = System.IO.File.ReadAllText(this.Host.ResolvePath("InterfaceImpl.cs")).Replace("InterfaceImpl", "DerivedClassA"); #>
<#= codeText #>

DerivedClassB.cs

 public partial class DerivedClassB : BaseClass, IInterface
    {
        public void BarFoo()
        {
            this.Bar();
            this.Foo();
        }
    }

DerivedClassBInterfaceImpl.tt

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<# var codeText = System.IO.File.ReadAllText(this.Host.ResolvePath("InterfaceImpl.cs")).Replace("InterfaceImpl", "DerivedClassB"); #>
<#= codeText #>

It's a little annoying that this requires creating a tt file for each derived class that wants to use the interface implementation, but it still saves on copy/paste code if InterfaceImpl.cs is more than a few lines of code. It's also probably possible to just create one tt file and specify the name of all the derived partial classes and generate multiple files.