我尽力搜索,但遗憾的是我没有学到任何相关内容;基本上我正在尝试解决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技能。提前感谢大家的耐心!
答案 0 :(得分:4)
除非我误解,否则你只需要一个界面。因此,只要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
答案 1 :(得分:2)
如果类没有共同的祖先并且具有不同的方法名称,则可以将每个类子类化,实现创建代理对象的公共接口。
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;
...
编辑:实施Steven Jeuris建议。在代理类中使用组合而不是继承。
答案 2 :(得分:2)
这就是我要做的事情:
这就是生成的代码:
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... }
}
答案 3 :(得分:0)
我建议为不同的类写一个共同的adapter。然后,您将拥有一个通用接口来处理访问所使用的特定命名基础属性/方法。
更新:
“refA,refB和refC中的每一个都将实现相同的属性和方法,但不同的名称。”
我解释说属性和方法的名称不同,但现在我猜你可能只是说refA refB和refC有不同的名字?
如果允许调整不同的实现,请为它们提供一个通用接口,并在整个代码中使用它,如其他答案中所述。否则,适配器可能仍然是一种可行的方法,或者您可以为它们中的每一个创建包装类,并实现所需的接口。
答案 4 :(得分:0)
在共享.NET程序集中声明接口。
创建从Interface继承的A,B和C类,并将它们放在不同的程序集中。
在主项目中使用Assembly.Load()来加载您想要使用的程序集。查找其中包含接口的类并创建实例。
答案 5 :(得分:0)
我建议如果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
答案 6 :(得分:0)
你确实需要一个接口。例如,考虑每个类提供方法doThis(),但RefA将其实现为(),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是RefA){ // ... }
答案 7 :(得分:0)
对factory pattern来说,这似乎是一个很好的机会。创建您的通用界面,将其提供给所有三个类,并启动正确的类。这些都受到界面的约束,所以你真的不必做任何太奇怪的事情。
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";
}
}