我有一個項目與兩個類庫。 我需要他們之間的編程像C#開關庫使用程序參數
if(arg == "a")
using LibraryA;
if(arg == "b")
using LibraryB;
namespace Project
{
public class MyClass
{
// my code here
}
}
我有一個項目與兩個類庫。 我需要他們之間的編程像C#開關庫使用程序參數
if(arg == "a")
using LibraryA;
if(arg == "b")
using LibraryB;
namespace Project
{
public class MyClass
{
// my code here
}
}
如果你想建立鬆散的夫婦應用程序切換,與應用程序的參數,我建議你閱讀更多關於扶養注塑模式。 這是一個不錯的article,描述如何建立這樣的設計。 (前4節課)
這是一個相當複雜的要求,你必須將多種模式結合在一起來實現這一點。我會盡量聯繫相關原則。
要解決的第一個問題是對齊兩個類庫,使它們具有通用接口。這是必要的,以便使它們可以互換,就像你描述的那樣。通常這與創建兩個對象實現的接口一樣簡單 - 但是您提到您只能控制其中一個庫。在這種情況下,您需要利用adapter pattern來強制您無法控制的庫來實現您的通用界面。
說,我們目前在Library1.dll
和Library2.dll
(Library1.dll是一個我們有超過控制)有這兩個類...
// in Library1.dll
public class Foo
{
public int DoSomething() { ... }
}
// In Library2.dll
public class Foo
{
public int DoSomething() { ... }
}
首先,我們需要定義我們的通用接口。這應該駐留在覈心/共享庫...
// In Shared.dll
public interface IFoo
{
int DoSomething();
}
,因爲現在我們有超過庫中的一個控制,我們可以很容易地實現它以通常的方式共同界面...
// In Library1.dll
public class Foo : IFoo
{
public int DoSomething() { ... }
}
但是由於我們無法控制Library2.dll
,我們需要創建一個適配器類。這個類的目的僅僅是實現通用接口,並且所有行爲都委託給真實的Library2.Foo
。實際上,這允許我們使Library2.Foo
對象實現我們的通用接口。
// In Shared.dll
public class Foo2Adapter : IFoo()
{
private Library2.Foo _realFoo;
public Foo2Adapter()
{
_realFoo= new Library2.Foo();
}
public int DoSomething()
{
_realFoo.DoSomething();
}
}
現在我們需要修改我們的所有客戶端代碼,以使用通用接口而不是直接使用對象。凡之前,你可能有這樣的事情...
if(arg == "a")
using LibraryA;
if(arg == "b")
using LibraryB;
namespace Project
{
public class MyClass
{
public void Bar()
{
var foo = new Foo();
foo.DoSomething();
}
}
}
現在你的代碼應該只使用界面......
namespace Project
{
public class MyClass
{
public void Bar(IFoo foo)
{
foo.DoSomething();
}
}
}
現在我們有一個新的問題,我們怎麼知道哪個版本的IFoo
使用?是Library1.Foo
還是Shared.Foo2Wrapper
?
您可以使用dependency injection來解決此問題。控制容器的反轉將爲您提供對象,您可以將其配置爲根據特定條件提供不同類型的對象。這裏有一個psuedocode示例,它使用了一個類似於StructureMap(我個人最喜歡的IoC容器)使用的sytax ...
var container = new IocContainer();
if (arg == "a")
container.For<IFoo>().Use<Library1.Foo>();
else if (arg == "b")
container.For<IFoo>().Use<Shared.Foo2Adapter>();
var foo = container.GetInstance<IFoo>();
現在,當我們調用GetInstance<IFoo>()
IoC容器將會給我們回無論是Library1.Foo
或Shared.Foo2Wrapper
取決於它是如何通過命令行配置。我們現在需要遍歷我們以前有new Foo()
的客戶代碼中的所有地方,並將其替換爲container.GetInstance<IFoo>()
。
我希望能讓你感動:)
下面是一個如何實現你的目標的例子。
using System;
namespace StackOverflowDemo.Applications.TestFrameworkDemo.Data
{
public interface IDataSource
{
string GetTitle(int id);
}
public class Database: IDataSource
{
public string GetTitle(int id)
{
string result;
//logic to connect to a database and retrieve a value would go here
switch (id)
{
case 1: result = "DB First Title"; break;
case 2: result = "DB Second Title"; break;
default: throw new KeyNotFoundException(string.Format("ID '{0}' not found",id));
}
return result;
}
}
}
using System;
using StackOverflowDemo.Applications.TestFrameworkDemo.Data;
namespace StackOverflowDemo.Applications.TestFrameworkDemo.DataTest
{
public class DatabaseMock : IDataSource
{
public string GetTitle(int id)
{
string result;
switch (id)
{
case 1: result = "DBMock First Title"; break;
case 2: result = "DBMock Second Title"; break;
default: throw new KeyNotFoundException(string.Format("ID '{0}' not found", id));
}
return result;
}
}
}
using System;
using StackOverflowDemo.Applications.TestFrameworkDemo.Data;
namespace StackOverflowDemo.Applications.TestFrameworkDemo.Logic
{
public class SomeBusinessObject
{
private IDataSource myData;
public SomeBusinessObject(IDataSource myData)
{
this.myData = myData;
}
public void OutputTitle(int id)
{
Console.WriteLine(myData.GetTitle(id));
}
}
}
using System;
using StackOverflowDemo.Applications.TestFrameworkDemo.Data;
//using StackOverflowDemo.Applications.TestFrameworkDemo.DataTest; //we don't need the using statement if we use the whole path below, which I think relates to your question
using StackOverflowDemo.Applications.TestFrameworkDemo.Logic;
namespace StackOverflowDemo.Applications.TestFrameworkDemo
{
class Program
{
public static void Main(string[] args)
{
IDataSource myData;
#if(DEBUG)
myData = new StackOverflowDemo.Applications.TestFrameworkDemo.DataTest.DatabaseMock();
#else
myData = new Database();
#endif
SomeBusinessObject sbo = new SomeBusinessObject(myData);
sbo.OutputTitle(1);
Console.WriteLine("Done");
Console.ReadKey();
}
}
}
上嘲笑更多信息,請訪問:http://msdn.microsoft.com/en-us/library/ff650441.aspx
還有的東西負載在Channel9的:http://channel9.msdn.com/search?term=test+driven+development
或者您可能感興趣的是:http://msdn.microsoft.com/en-us/library/hh549175(v=vs.110).aspx。它允許你劫持現有對象的方法並用虛擬方法替換它們。我還沒有玩過,但看起來很有希望。
爲什麼你需要這個?爲什麼不參考他們兩個? –
它非常複雜,你參考兩個庫,稍後根據參數使用它。 – andy
如果您在代碼中引用具體類型(而不是接口),那麼特定的類型或變量在編譯時就會被修復。這些庫之間是否有共同點(大概是命名空間和類型名稱)? –