简体   繁体   English

具有不同类型的接口的实现?

[英]Implementations of an Interface with Different Types?

Searched as best I could but unfortunately I've learned nothing relevant; 我已尽力进行搜索,但不幸的是,我没有发现任何相关信息。 basically I'm trying to work around the following problem in C#... 基本上我正在尝试解决C#中的以下问题...

For example, I have three possible references (refA, refB, refC) and I need to load the correct one depending on a configuration option. 例如,我有三个可能的引用(refA,refB,refC),我需要根据配置选项加载正确的引用。 So far however I can't see a way of doing it that doesn't require me to use the name of said referenced object all through the code (the referenced objects are provided, I can't change them). 但是到目前为止,我还看不到一种方法,不需要我在整个代码中都使用所述引用对象的名称(提供了引用对象,我无法更改它们)。 Hope the following code makes more sense: 希望以下代码更有意义:

public ??? LoadedClass;

public Init()
    {
        /* load the object, according to which version we need... */
        if (Config.Version == "refA")
        {
            Namespace.refA LoadedClass = new refA();
        }
        else if (Config.Version == "refB")
        {
            Namespace.refB LoadedClass = new refB();
        }
        else if (Config.Version == "refC")
        {
            Namespace.refC LoadedClass = new refC();
        }

        Run();
    }
private void Run(){
    {
        LoadedClass.SomeProperty...
        LoadedClass.SomeMethod(){ etc... }
    }

As you can see, I need the Loaded class to be public, so in my limited way I'm trying to change the type 'dynamically' as I load in which real class I want. 如您所见,我需要Loaded类是公共的,因此我以有限的方式尝试在加载所需的真实类时“动态”更改类型。 Each of refA, refB and refC will implement the same properties and methods but with different names. refA,refB和refC中的每一个都将实现相同的属性和方法,但名称不同。 Again, this is what I'm working with, not by my design. 同样,这是我正在使用的内容,而不是我的设计。

All that said, I tried to get my head around Interfaces (which sound like they're what I'm after) but I'm looking at them and seeing strict types - which makes sense to me, even if it's not useful to me. 所有这些,我试图绕过Interfaces(听起来像是我所追求的),但是我正在查看它们并看到严格的类型-这对我来说很有意义,即使它对我没有用。

Any and all ideas and opinions are welcome and I'll clarify anything if necessary. 欢迎任何想法和意见,如有必要,我将澄清。 Excuse any silly mistakes I've made in the terminology, I'm learning all this for the first time. 请原谅我在术语上犯的任何愚蠢的错误,这是我第一次学习所有这些内容。 I'm really enjoying working with an OOP language so far though - coming from PHP this stuff is blowing my mind :-) 到目前为止,我真的很喜欢使用OOP语言-来自PHP的东西让我很惊讶:-)

EDIT 编辑

Sorry for not making it clear at all, but each of refA, refB, refC has unique types for their methods, even though they're the essentially the same method functionality wise (the idea being they're versioned). 抱歉,一点儿也没有清楚,但是refA,refB和refC的方法都有唯一的类型,即使它们在功能上本质上是相同的(想法是对它们进行版本控制)。 This means with an interface, in my mind, I'm left with: 这意味着在我的脑海中,我剩下的是:

public interface IRef
    {
        SomeType<<RefA,RefB,RefC,???>> SomeProperty {get;}
        void SomeMethod();
    }

Thanks to GenericTypeTea for the starting Interface point. 感谢GenericTypeTea作为起始接口点。 I may be trying to do something that's not recommended/not possible... The underlying problem is I need to support different versions (as per the configuration option) from the same program; 我可能正在尝试执行不建议/不可能执行的操作...根本的问题是我需要从同一程序支持不同版本(根据配置选项)。 or I'm going to be developing 'different' programs for each version and that's just a big horrible mess :-) 否则我将为每个版本开发“不同的”程序,那简直是一团糟:-)

EDIT 2 编辑2

public interface Sage
    {
        SageDataObject???.SDOEngine sdo;
    }

class SageObj150 : Sage
    {
        SageDataObject150.SDOEngine sdo = new SageDataObject150.SDOEngine();
    }

class SageObj160 : Sage
    {
        SageDataObject160.SDOEngine sdo = new SageDataObject160.SDOEngine();
    }

class SageObj170 : Sage
    {
        SageDataObject170.SDOEngine sdo = new SageDataObject170.SDOEngine();
    }

Where SDOEngine() (I've only just seen) is an interface itself - which I think just confused things greatly. SDOEngine()(我刚刚才看过)本身就是一个接口-我认为这使事情非常混乱。 Thought I was doing pretty well to write the whole application starting with no knowledge of C# but this now seems beyond my Google skills. 以为我在不了解C#的情况下编写整个应用程序就做得不错,但是现在看来这超出了我的Google技能。 Thanks in advance for everyone's patience! 在此先感谢大家的耐心配合!

Unless I've misunderstood, you just need an interface. 除非我误解了,否则您只需要一个接口即可。 So as long as RefA-C implement the same properties and methods, you'll be fine: 因此,只要RefA-C实现相同的属性和方法,就可以了:

public interface IRef
{
   string SomeProperty {get;}
   void SomeMethod();
}

Then implement the interface for RefA-C: 然后实现RefA-C的接口:

public class RefA : IRef
{
    public string SomeProperty {get;}

    public void SomeMethod()
    {
       // Do for A
    }
}

public class RefB : IRef
{
    public string SomeProperty {get;}

    public void SomeMethod()
    {
       // Do for B
    }
}

Then you can refer to the interface as the interface of the implementation: 然后,您可以将接口称为实现的接口:

public IRef LoadedClass;

And instantiate it as follows: 并实例化如下:

if (UseConfigA) LoadedClass = new RefA(); // etc

If the classes doesn't have a common ancestor and have different method names you might subclass each of them, implementing a common interface creating a proxy object. 如果这些类没有一个共同的祖先,并且具有不同的方法名,则可以将它们每个子类化,实现一个创建代理对象的共同接口。

interface ICommonFunctions
{
   void MethodA();

   void MethodB();
}

class ProxyRefA : ICommonFunctions
{
    refA proxyObj = new refA;

    void MethodA() { proxyObj.methodWithOtherName(); }

    void MethodB() { proxyObj.otherMethodName(); }
}

/* The same for refB and refC */

And so on. 等等。

This way on your original code you can have: 通过这种方式,您可以在原始代码中拥有:

public ICommonFunctions LoadedClass;

...

EDIT : Implementing Steven Jeuris suggestion. 编辑 :实施史蒂文·杰里斯的建议。 Using composition instead of inheritance in the proxy class. 在代理类中使用合成代替继承。

Here's what I would do: 这就是我要做的:

  1. Create an interface (let's call it ICommonStuff) that has all of the properties and methods that are shared between refA, refB and refC. 创建一个具有在refA,refB和refC之间共享的所有属性和方法的接口(我们称为ICommonStuff)。
  2. For each of refA, refB and refC, create a wrapper class that accepts the type as an argument and implements the interface ICommonStuff. 对于refA,refB和refC中的每一个,创建一个包装器类,该包装器类接受该类型作为参数并实现接口ICommonStuff。
  3. Implement your Init method largely as you have already, except instead of setting the LoadedClass property to a refA, refB or refC directly, set it to one of the wrappers. 除了没有将LoadedClass属性直接设置为refA,refB或refC之外,还应将其设置为包装器之一,这与您已经实现的方法大体相同。

And this is what the resultant code would be: 这就是生成的代码:

public ICommonStuff LoadedClass;

public Init()
{
    /* load the object, according to which version we need... */
    if (Config.Version == "refA")
    {
        LoadedClass = new WrapperA(new refA());
    }
    else if (Config.Version == "refB")
    {
        LoadedClass = new WrapperB(new refB());
    }
    else if (Config.Version == "refC")
    {
        LoadedClass = new WrapperC(new refC());
    }
    Run();
}
private void Run(){
{
    LoadedClass.SomeProperty...
    LoadedClass.SomeMethod(){ etc... }
}

I suggest writing one common adapter for the different classes. 我建议为不同的类编写一个通用适配器 You then have your one common interface which handles accessing the specific named underlying property/method used. 然后,您将拥有一个通用接口,该接口可处理访问所使用的特定命名基础属性/方法。

UPDATE: 更新:

"Each of refA, refB and refC will implement the same properties and methods but with different names ." “每个refA,refB和refC都将实现相同的属性和方法,但名称不同 。”

I interpreted that the names of the properties and methods are different, but now I'm guessing you probably only mean that refA refB and refC have different names? 我解释说属性和方法的名称不同,但是现在我猜您可能仅表示refA refB和refC具有不同的名称?

If you are allowed to adjust the different implementations , give them a common interface, and use this throughout your code, as mentioned in the other answers. 如果允许您调整不同的实现 ,请为它们提供一个通用接口,并在整个代码中使用它,如其他答案所述。 Otherwise the adapter might still be a feasible approach, or you could create a wrapper class for every one of them, and implement the required interface. 否则,适配器可能仍然是可行的方法,或者您可以为每个适配器创建一个包装器类 ,并实现所需的接口。

Declare Interface in shared .NET assembly. 声明共享.NET程序集中的接口。

Create A, B and C classes inherited from the Interface and place them in different assemblies. 创建从接口继承的A,B和C类,并将它们放在不同的程序集中。

Use Assembly.Load() in main project to load assembly you want use. 在主项目中使用Assembly.Load()加载要使用的程序集。 Find class inhereted from the Interface in it and create instance. 从接口中找到该类中的类并创建实例。

I would suggest that if the 3 different types share a common interface then they should implement a common interface. 我建议,如果3种不同类型共享一个公共接口,那么它们应该实现一个公共接口。 For example, IExample 例如, IExample

Then you can load the right implementation instance from your config file. 然后,您可以从配置文件中加载正确的实施实例。

// public fields are a no-no, use properties instead
public IExample LoadedClass { get; private set; } 

. . .

LoadedClass = (IExample)Activator.CreateInstance(Config.Version);

Where Config.Version is the full name of your class eg Namespace.RefA 其中Config.Version是类的全名,例如Namespace.RefA

You indeed need an interface for this. 您确实需要一个接口。 consider for example that each class provides a method doThis(), but RefA implements it as a(), RefB implements it as b() and RefC implements it as c(). 例如,考虑每个类提供一个doThis()方法,但RefA将其实现为a(),RefB将其实现为b(),而RefC将其实现为c()。 You can think of interfaces as abstract class which cannot provide any code, but of which a class can inheret multiple. 您可以将接口视为无法提供任何代码的抽象类,但是一个类可以在其中插入多个代码。

You can make an interface as follows: 您可以按如下方式创建界面:

interface CanDoThis{
    public void doThis();
}

You then need to modify the class files as follows: 然后,您需要按如下所示修改类文件:

public class RefA : CanDoThis // this means "I implement the interface CanDoThis"
{
    // Add this method, it is needed for the interface
    public void doThis(){
        a();
    }

    public void a(){
        // this has already been provided in the origional class file
    }
}

And likewise for RefB and RefC. 对于RefB和RefC同样如此。 Your code then becomes: 您的代码将变为:

public CanDoThis loadedClass;

public Init()
{
    /* load the object, according to which version we need... */
    if (Config.Version == "refA")
    {
        loadedClass = new RefA();
    }
    // etc
}

be aware that you will only be able to call methods that are defined in the interface, so each method you want to call needs to be defined in the interface. 请注意,您将只能调用接口中定义的方法,因此需要在接口中定义要调用的每个方法。

You shouldn't need it if you program well, but if you ever want to check which class the instance is of you can just use the standard "is" just as you would with subclasses: if(loadedClass is RefA){ //... } 如果您编写的程序不错,则不需要它,但是如果您想检查实例所属的类,则可以像使用子类一样使用标准的“ is”:if(loadedClass is RefA){//。 ..}

Looks like a good opportunity for the factory pattern to me. 对我来说,这似乎是一个恢复工厂模式的好机会。 Create your common interface, give it to all three classes, and spin up the correct class. 创建您的通用接口,将其分配给所有三个类,然后旋转正确的类。 These are bound by the interface so you don't really have to do anything too weird. 这些都是受界面约束的,因此您不必做任何太怪异的事情。

class Program
    {
        static void Main(string[] args)
        {
            RefFactory factory = new RefFactory();
            ICommonFunctionality a = factory.Create(0);
            Console.WriteLine(a.SomeMethod());

            ICommonFunctionality b = factory.Create(1);
            Console.WriteLine(b.SomeMethod());

            ICommonFunctionality c = factory.Create(2);
            Console.WriteLine(c.SomeMethod());

            //The above is to just test. Should be something like this:
            ICommonFunctionality Ref;

            if (1 == 1)
            {
                Ref = factory.Create(0);
            }
            if (1 == 2)
            {
                Ref = factory.Create(1);
            }

            //etc..

            Console.Read();
        }
    }

    public class RefFactory
    {
        public ICommonFunctionality Create(int someCondition)
        {
            if (someCondition == 0)
            {
                return new RefA();
            }
            else if (someCondition == 1)
            {
                return new RefB();
            }
            else
            {
                return new RefC();
            }
        }
    }

    public interface ICommonFunctionality
    {
        bool SomeProperty { get; set; }
        string SomeMethod();
    }

    public class RefA : ICommonFunctionality
    {
        public bool SomeProperty { get; set; }
        public string SomeMethod()
        {
            return "RefA";
        }
    }

    public class RefB : ICommonFunctionality
    {
        public bool SomeProperty { get; set; }
        public string SomeMethod()
        {
            return "RefB";
        }
    }

    public class RefC : ICommonFunctionality
    {
        public bool SomeProperty { get; set; }
        public string SomeMethod()
        {
            return "RefC";
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM