繁体   English   中英

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

[英]Implementations of an Interface with Different Types?

我已尽力进行搜索,但不幸的是,我没有发现任何相关信息。 基本上我正在尝试解决C#中的以下问题...

例如,我有三个可能的引用(refA,refB,refC),我需要根据配置选项加载正确的引用。 但是到目前为止,我还看不到一种方法,不需要我在整个代码中都使用所述引用对象的名称(提供了引用对象,我无法更改它们)。 希望以下代码更有意义:

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... }
    }

如您所见,我需要Loaded类是公共的,因此我以有限的方式尝试在加载所需的真实类时“动态”更改类型。 refA,refB和refC中的每一个都将实现相同的属性和方法,但名称不同。 同样,这是我正在使用的内容,而不是我的设计。

所有这些,我试图绕过Interfaces(听起来像是我所追求的),但是我正在查看它们并看到严格的类型-这对我来说很有意义,即使它对我没有用。

欢迎任何想法和意见,如有必要,我将澄清。 请原谅我在术语上犯的任何愚蠢的错误,这是我第一次学习所有这些内容。 到目前为止,我真的很喜欢使用OOP语言-来自PHP的东西让我很惊讶:-)

编辑

抱歉,一点儿也没有清楚,但是refA,refB和refC的方法都有唯一的类型,即使它们在功能上本质上是相同的(想法是对它们进行版本控制)。 这意味着在我的脑海中,我剩下的是:

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

感谢GenericTypeTea作为起始接口点。 我可能正在尝试执行不建议/不可能执行的操作...根本的问题是我需要从同一程序支持不同版本(根据配置选项)。 否则我将为每个版本开发“不同的”程序,那简直是一团糟:-)

编辑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();
    }

SDOEngine()(我刚刚才看过)本身就是一个接口-我认为这使事情非常混乱。 以为我在不了解C#的情况下编写整个应用程序就做得不错,但是现在看来这超出了我的Google技能。 在此先感谢大家的耐心配合!

除非我误解了,否则您只需要一个接口即可。 因此,只要RefA-C实现相同的属性和方法,就可以了:

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

然后实现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
    }
}

然后,您可以将接口称为实现的接口:

public IRef LoadedClass;

并实例化如下:

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

如果这些类没有一个共同的祖先,并且具有不同的方法名,则可以将它们每个子类化,实现一个创建代理对象的共同接口。

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 */

等等。

通过这种方式,您可以在原始代码中拥有:

public ICommonFunctions LoadedClass;

...

编辑 :实施史蒂文·杰里斯的建议。 在代理类中使用合成代替继承。

这就是我要做的:

  1. 创建一个具有在refA,refB和refC之间共享的所有属性和方法的接口(我们称为ICommonStuff)。
  2. 对于refA,refB和refC中的每一个,创建一个包装器类,该包装器类接受该类型作为参数并实现接口ICommonStuff。
  3. 除了没有将LoadedClass属性直接设置为refA,refB或refC之外,还应将其设置为包装器之一,这与您已经实现的方法大体相同。

这就是生成的代码:

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... }
}

我建议为不同的类编写一个通用适配器 然后,您将拥有一个通用接口,该接口可处理访问所使用的特定命名基础属性/方法。

更新:

“每个refA,refB和refC都将实现相同的属性和方法,但名称不同 。”

我解释说属性和方法的名称不同,但是现在我猜您可能仅表示refA refB和refC具有不同的名称?

如果允许您调整不同的实现 ,请为它们提供一个通用接口,并在整个代码中使用它,如其他答案所述。 否则,适配器可能仍然是可行的方法,或者您可以为每个适配器创建一个包装器类 ,并实现所需的接口。

声明共享.NET程序集中的接口。

创建从接口继承的A,B和C类,并将它们放在不同的程序集中。

在主项目中使用Assembly.Load()加载要使用的程序集。 从接口中找到该类中的类并创建实例。

我建议,如果3种不同类型共享一个公共接口,那么它们应该实现一个公共接口。 例如, IExample

然后,您可以从配置文件中加载正确的实施实例。

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

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

其中Config.Version是类的全名,例如Namespace.RefA

您确实需要一个接口。 例如,考虑每个类提供一个doThis()方法,但RefA将其实现为a(),RefB将其实现为b(),而RefC将其实现为c()。 您可以将接口视为无法提供任何代码的抽象类,但是一个类可以在其中插入多个代码。

您可以按如下方式创建界面:

interface CanDoThis{
    public void doThis();
}

然后,您需要按如下所示修改类文件:

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
    }
}

对于RefB和RefC同样如此。 您的代码将变为:

public CanDoThis loadedClass;

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

请注意,您将只能调用接口中定义的方法,因此需要在接口中定义要调用的每个方法。

如果您编写的程序不错,则不需要它,但是如果您想检查实例所属的类,则可以像使用子类一样使用标准的“ is”:if(loadedClass is RefA){//。 ..}

对我来说,这似乎是一个恢复工厂模式的好机会。 创建您的通用接口,将其分配给所有三个类,然后旋转正确的类。 这些都是受界面约束的,因此您不必做任何太怪异的事情。

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