Exposing C# Code to VBA GetAutomationMethod Error - c#

I am a relatively new coder and have never worked with C# or VBA before. I am currently trying to expose my C# code to VBA. I have been following the MSDN guide on how to do that.
I am running into an error when it comes to overriding my method:
public class AsynchronousClient : IAsynchronousClient {
protected override object GetAutomationObject(){
return this;
}
}
The error is:
'AsynchronousClient.GetAutomationObject()': no suitable method found to override.
I have been able to extract the interface and added the COMVisibleAttributes to my interface.
Any help or additional guidance on how to amend the code would be appreciated.

As mentioned by others, the steps you're following are specific to the VSTO technology, not for creating a DLL to use with VBA. Quite honestly, if you've never coded in either language before, this is probably not the best thing to start with...
Start with a Class project. You need GUIDs. You need an Interface, which your class needs to implement. And you need to specify how the class should work with the Interface. It needs to be set to the Type "None" for the Intellisense, etc. to work. The DLL needs to be COM-registered, as well.
Here's some test code I use, to give you an idea how the code part looks
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using vbForm = Microsoft.Vbe.Interop.Forms;
using office = Microsoft.Office.Core;
//[assembly: Guid("B5C4D7F5-C9B2-491e-91BA-63C208959190")]
namespace COM_ClassLib_CS
{
[Guid("BF78EB64-F59B-4086-9FC5-B87AA2002F4F")]
[ComVisible(true)]
public interface IVBAExtensions
{
string getTest(object app);
void formData(object formControl);
void passWordDoc(object doc);
object[,] returnArray();
string returnString();
}
[Guid("EC0B623E-E8A0-4564-84FB-2D8D149C8BA7")]
[ClassInterface(ClassInterfaceType.None)]
[ComVisible(true)]
public class VBAExtensions : IVBAExtensions
{
public VBAExtensions()
{
}
//test using late-binding
public string getTest(object app)
{
object xlApp = app.GetType().InvokeMember("Application", System.Reflection.BindingFlags.GetProperty, null,
app, null);
object nm = xlApp.GetType().InvokeMember("Name", System.Reflection.BindingFlags.GetProperty, null,
xlApp, null);
string appName = nm.ToString();
object isReady = xlApp.GetType().InvokeMember("Ready", System.Reflection.BindingFlags.GetProperty, null,
xlApp, null);
string sReady = isReady.ToString();
return sReady;
}
//test calling from a UserForm, passing control as argument
public void formData(object formControl)
{
//string data = "";
vbForm.TextBox t = formControl as vbForm.TextBox;
t.Text = "test";
//return data;
}
//test passing doc object and accessing its Window
public void passWordDoc(object doc)
{
Microsoft.Office.Interop.Word.Document WordDoc = doc as Microsoft.Office.Interop.Word.Document;
WordDoc.ActiveWindow.Caption = "Tested!";
}
//test returning an array to VBA calling procedure
public object[,] returnArray()
{
//object[] array = new object[2] {"a", "b"};
object[,] array = new object[2, 2];
array[0, 0] = "a";
array[0, 1] = "1";
array[1, 0] = "b";
array[1, 1] = "2";
return array;
}
//test returning a string to VBA calling procedure
public string returnString()
{
return "AbC";
}
}
}
For more information you can reference https://msdn.microsoft.com/en-us/library/c3fd4a20.aspx and https://msdn.microsoft.com/en-us/library/ms973802.aspx

Your AsynchronousClient class is implementing the IAsynchronousClient interface, which I presume looks like this:
public interface IAsynchronousClient
{
object GetAutomationObject();
}
You would implement it like this:
public class AsynchronousClient : IAsynchronousClient
{
public object GetAutomationObject()
{
return this;
}
}
The error message says exactly what the problem is: there's nothing to override there. You use the override method when you're implementing abstract or virtual methods, not interface members.
Remove the override keyword and you'll be good. Below snippets show situations where override would be applicable:
public abstract class AsynchronousClientBase
{
public abstract object GetAutomationObject();
public virtual object GetFoo()
{
return null;
}
}
public class AsynchronousClient : AsynchronousClientBase
{
public override object GetAutomationObject()
{
return this;
}
public override object GetFoo()
{
return new Foo();
}
}
The MSDN article you linked to says to "Override the GetAutomationObject method of a host item class in your project" - this implies your type should be derived from a base class that defines a virtual or abstract GetAutomationObject method.

Related

Using Dependency Injection for classes instantiated at run time

I have two classes: ImportBase.cs (Parent) and ImportFleet.cs (Child) which will in the future import a CSV file. Each child of ImportBase will implement a different implementation of the actual import code.
The approriate child class to use is determined in a Service class where the correct class is instantiated and the import method called. All is going well up until this point.
The problem is that I also want to Dependency Inject some repository classes into ImportBase and it's inherited classes (as I have attempted in the code below):
ImportBase.cs
namespace WebApi.Services.Import.Investments
{
interface IImport
{
public void Import(IFormFile file, int UserId);
}
public abstract class ImportBase : IImport
{
public abstract void Import(IFormFile file, int UserId);
protected List<InvestmentTransactionType> transactionTypes = new();
protected IInvestmentEntityRepository _investmentEntityRepository;
public ImportBase(IInvestmentEntityRepository investmentEntityRepository)
{
_investmentEntityRepository = investmentEntityRepository;
}
}
}
ImportFleet.cs
namespace WebApi.Services.Import.Investments
{
public class ImportFleet : ImportBase
{
public ImportFleet(IInvestmentEntityRepository investmentEntityRepository) : base(investmentEntityRepository)
{
}
public override void Import(IFormFile file, int UserId)
{
}
}
}
InvestmentService.cs
namespace WebApi.Services
{
public interface IInvestmentService
{
public void Import(IFormFile file, int UserId, int InvestmentEntityId);
}
public class InvestmentService: IInvestmentService
{
public void Import(IFormFile file, int UserId, int InvestmentEntityId)
{
IImport importService = null;
string investmentEntity = ImportBase.determineInvestmentEntityFromCsv(file);
switch(investmentEntity)
{
case "fleet":
importService = new ImportFleet(); // problem is here
break;
}
if (importService != null)
{
importService.Import(file, UserId);
}
}
}
}
The problem is the following line:
importService = new ImportKuflink();
Because I only determine which child class to instantiate at run time, I cannot take advantage of DI here.
Under normal circumstances I would make the Import classes a DI based service so all dependencies are available, however I have to create the instance at run time so this I don't think is possible.
Is there a way to accomplish the above?
Here's a simplified version of your code that demonstrates how you can populate an instance of an object from a DI service container.
In your InvestmentService:
Inject the IServiceProvider.
Use the little known utility ActivatorUtilities to get a fully DI'd instance of your object.
Make sure you dispose it properly if it implemenents IDisposable. I've included an async version if you use anything that needs a IAsyncDisposable.
public class InvestmentService : IInvestmentService
{
private IServiceProvider _serviceProvider;
public InvestmentService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
//...
}
public Import()
{
IImport? importService = null;
IDisposable? disposable = null;
var importFleet = ActivatorUtilities.CreateInstance<ImportFleet>(_serviceProvider);
if (importFleet is IDisposable)
disposable = importFleet as IDisposable;
importService = importFleet as IImport;
// Do whatever you want to do with it
disposable?.Dispose();
}
public async ValueTask ImportAsync()
{
IImport? importService = null;
IDisposable? disposable = null;
IAsyncDisposable? asyncDisposable = null;
var importFleet = ActivatorUtilities.CreateInstance<ImportFleet>(_serviceProvider);
if (importFleet is IDisposable)
disposable = importFleet as IDisposable;
if (importFleet is IAsyncDisposable)
asyncDisposable = importFleet as IAsyncDisposable;
importService = importFleet as IImport;
// Do whatever you want to do with it
disposable?.Dispose();
if (asyncDisposable is not null)
await asyncDisposable.DisposeAsync();
}
}
Yes, of course there is a way to accomplish this. But I guess the DI container you are using (like from MS) won't help you here.
I've been fiddling with crap like this for like two years so far and still am busy with it. Two years of creating my own IoC framework.
Usual DI/IoC microkernels follow OCP and other really mandatory concepts and patterns. What I've done is leaving one single small door open. I won't bore you with details. The fundamental idea is that a class must be decorated with the appropriate attributes in code, and then is able to call the microkernel within its constructor (which has been called by a simple "var foo = new Barney();") to let an entity be modified like it had been created by the microkernel.
There is no(t yet a) way to hook into the plain new() code. Some cheer this, some don't. I'm with the cheerleaders here. Why? Side-effects.
Imagine this:
public class SomeNumber
{
public int SomeValue { get; private set; }
public SomeNumber()
{
SomeValue = 19;
}
}
Okay? Let's assume you'd modified the new() process by whatever, then another user of your code goes:
Assert.AreEqual(19, someNumberEntity.SomeNumber);
and this code throws an exception, because for whatever reason your modifying code set the number to 7.
Now look at this code (from a unit test):
using System.Reflection;
using Kis.Core.Attributes;
namespace UnitTests_Kis.Core
{
[KisAware]
public class KisAwareSimpleClass
{
[Property(value: 123)]
public int ValueToCheck { get; set; } = 0;
[Property(value: "I am the doctor!")]
public string Name { get; set; } = "";
public KisAwareSimpleClass()
{
var t = this.GetType();
var fqtn = t.FullName;
var ec = new Kis.Core.EntityCreator(Assembly.GetAssembly(t));
ec.ModifyExistingEntity(fullyQualifiedTypeName: fqtn, existingEntity: this);
}
}
}
Clean code isn't always easily readable, but the aspects/attributes will raise coder's awareness.
PS: I posted the unit test code on purpose to show you what's happening.
Short version:
Microkernel.Modify(this);
You can inject a factory which has the services injected into it.
public interface IImportFactory
{
ImportFleet CreateFleetImporter();
}
public class MyImportFactory : IImportFactory
{
private readonly IMyDependency1 _dependency1;
private readonly IMyDependency2 _dependency2;
public MyImportFactory(IMyDependency1 dependency1, IMyDependency2 dependency2)
{
_dependency1 = dependency1;
_dependency2 = dependency2;
}
public ImportFleet CreateFleetImporter()
{
return new ImportFleet(_dependency1, _dependency2);
}
}
Then inject the factory as a dependency in your Service class.

Having similar method name with same parameter inside a class just with Interface name change

Just came across a code where a method with the same name is implemented within the class twice.
Once with the name only
Second with the Interface name and then the method name.
What is the concept called? I am unable to find the right direction. And if someone can explain it that would be great.
// Online C# Editor for free
// Write, Edit and Run your C# code using C# Online Compiler
using System;
public class HelloWorld
{
public static void Main(string[] args)
{
var obj = new AuthClass();
Console.WriteLine(obj.Login());
var obj2 = new AuthClass() as IAuth;
Console.WriteLine(obj2.Login());
//------------
}
}
public class AuthClass : IAuth
{
public string Login()
{
return "Method : You can be a developer";
}
string IAuth.Login()
{
return "Interface: Please learn the concepts";
}
}
public interface IAuth
{
string Login();
}

Is there a better way in C# to reserve long variable name?

var test = Class1.Subclass1.Subclass2.PropertyNameWhichIsBigName
I have to use above in many places. How to avoid typing or save few key stroke? is there any shortcut in C#
Yes, you can use Namespace aliases:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/namespaces/using-namespaces
using ShortName = Class1.Subclass1.Subclass2;
And then
var test = ShortName.PropertyNameWhichIsBigName;
How about a function:
Func<typeOfProperty> someName = () => Class1.Subclass1.Subclass2.PropertyNameWhichIsBigName;
if you now call
var test = someName();
you would get your desired value without having to type the long chain of properties all the time.
Edit:
Just to be clear, if PropertyNameWhichIsBigName changes, someName() will return the new value.
You can use namespace aliasing and just call it in namespaces section in your code, and you can effectively use objects and functions all over the body #canton7 has already written example for that.
or you can use code blocks statements but you have to implement IDisposable, but this can limit your object calling section but you can get benefit fit automatic dispose.
class Class1
{
public class Subclass1
{
public class Subclass2 : IDisposable
{
public string PropertyNameWhichIsBigName { get; set; }
public void Dispose()
{
throw new NotImplementedException();
}
}
}
}
class Program
{
static void Main(string[] args)
{
using (Class1.Subclass1.Subclass2 obj = new Class1.Subclass1.Subclass2())
{
string propertiesValue = obj.PropertyNameWhichIsBigName;
}
}
}

How to implement Interface to an abstract class which is constraint?

A few days ago I've tried to use (reference) a QRCode library .net with no interface in ms access vba unsuccesfully. So I did some research and people here guided me.
So I decided to make the interface I followed this steps
https://whoisburiedhere.wordpress.com/2011/07/12/creating-a-com-object-from-scratch-with-c/
I've been able to see the intellisense and create some of the objects and variables of other classess but I'm trouble with a class in which I see the Dispose() but I can't use the New in ms access:
[Dim QRCD as New QRCode]
I get an error the use of New is not valid but I can declare with the line:
Dim QRCD as QRCode
[I think that's not an object{ If I try to make it equals to QRData "That is no permited" error kicks in}] that class implements an abstract class which has constraints I've tried to put the interface in the abstract class and I get the error "Does not implement the method" if I put it in the Child class I can't create an object neither see any of the methods with the late binding.
The QRCoder library can be found here.
https://github.com/codebude/QRCoder
This is the abstract class as it's provided.
{
using System;
public abstract class AbstractQRCode<T>
{
protected QRCodeData qrCodeData;
protected AbstractQRCode(QRCodeData data)
{
qrCodeData = data;
}
public abstract T GetGraphic(int pixelsPerModule);
}
}
This is the child class that implements it; it's already modified with the interface. Is not all the code but down are several methods all called GetGraphic(something as something) which are different from one another.
[ComVisible(true)]
[Guid("It's filled in the program"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface neker
{
Bitmap GetGraphic(int pixelsPerModule);
}
[ComVisible(true)]
[Guid(""), ClassInterface(ClassInterfaceType.AutoDual)]
public class QRCode :AbstractQRCode<Bitmap>, IDisposable, neker
{
public QRCode(QRCodeData data) : base(data) {}
public override Bitmap GetGraphic(int pixelsPerModule)
{
return GetGraphic(pixelsPerModule, Color.Black, Color.White, true);
}
public Bitmap GetGraphic(int pixelsPerModule, string darkColorHtmlHex, string lightColorHtmlHex, bool drawQuietZones = true)
{
return GetGraphic(pixelsPerModule, ColorTranslator.FromHtml(darkColorHtmlHex), ColorTranslator.FromHtml(lightColorHtmlHex), true);
}
This is the sample code (also provided)
QRCodeGenerator qrGenerator = new QRCodeGenerator();
QRCodeData qrCodeData = qrGenerator.CreateQrCode("The text which should be encoded.", QRCodeGenerator.ECCLevel.Q);
QRCode qrCode = new QRCode(qrCodeData);
Bitmap qrCodeImage = qrCode.GetGraphic(20);
This is my code in VBA [This is in a Module]
Public Sub QRCreator(QRtext As String)
Dim QRCG As QRCoder.QRCodeGenerator
Set QRCG = New QRCoder.QRCodeGenerator
Dim QRCD As QRCodeData
Set QRCD = QRCG.CreateQRCode(QRtext, ECCLevel_Q, False)
Dim QRCO As QRCode
Set QRCO = Factory.CreateQRCode(QRCD)
Forms!Formulario1.[Oleobject].Picture = QRCO.GetGraphic(5)
End Sub
Public Sub InitiateProperties(Data As QRCodeData)
//I declared it as Variant since QRCode is not avaliable
Dim m_data As Variant
m_data = Data
End Sub
This is in another module[I use this modules to create the object with parameters] Pass arguments to Constructor in VBA
Public Function CreateQRCode(Data As QRCodeData) As QRCode
//you see the word new is missing If I run it it says "An object is required"
Set CreateQRCode = QRCode
CreateQRCode.InitiateProperties Data:=Data
End Function
How could I modify it to be usable from microsoft access 2013?
Is another way to do it with no interfaces?
Does access supports bitmaps in vba?
I'm very new with all this stuff so thank you so much.
EDIT:
THE REASON WHY I COULD'T MAKE IT WORK WAS COM VISIBLE DOESN´T SUPPORT CONSTRUCTORS WITH PARAMETERS, AND METHODS WITH OVERRIDES. THE ANSWER THEN IS HOW I WAS ABLE TO CREATE THE IMAGES ANYWAY.
Your COM object can't be created because the class doesn't have a default constructor. Rather than trying to expose the original API, you should create a single class with the methods matching your needs:
VBA usage:
Public Sub QRCreator(text As String)
Dim qrc As New QRCoder.QRCodeGenerator
Forms!Formulario1.[Oleobject].Picture = qrc.Create(text, CCLevel_Q, 5)
End Sub
.Net :
[Guid("C7CC4CA0-813A-431E-B92C-842A07735E72")]
[ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface _QRCodeGenerator {
public IStdPicture Create(string text, int cclevel, int pixelsPerModule);
}
[ProgId("QRCoder.QRCodeGenerator")]
[Guid("4DC2C1F8-2727-4120-80E1-8475650D8547")]
[ComVisible(true), ClassInterface(ClassInterfaceType.None)]
[Description("...")]
public class QRCodeGenerator : _QRCodeGenerator, IDisposable {
private QRCoder.QRCodeGenerator instance;
public QRCodeGenerator() {
instance = new QRCoder.QRCodeGenerator();
}
public IStdPicture Create(string text, int cclevel, int pixelsPerModule){
var qrCodeData = instance.CreateQrCode(text, cclevel);
var qrCode = new QRCoder.QRCode(qrCodeData);
var bitmap = qrCode.GetGraphic(pixelsPerModule);
return ImageToPicture(bitmap);
}
public void Dispose() {
instance.Dispose();
}
private static IStdPicture ImageToPicture(Bitmap bitmap) {
...
}
}
Well After checking, trying and failing I decided to change my perspective. So I did this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Interop;
using System.Runtime.InteropServices;
using stdole;
namespace QRCoder
{
[Guid("52724C82-F18C-460B-B48D-1F19E016F86E")]
[ComVisible (true) , InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IQRCodeGene
{
string Create(string text, QRCodeGenerator.ECCLevel value, int pixelsPerModule);
}
[Guid("4F445AA5-D642-438B-A69A-429D621A3CB0")]
[ComVisible (true), ClassInterface(ClassInterfaceType.None)]
public class QRCodeGene: IQRCodeGene, IDisposable
{
private QRCodeGenerator Instance;
public QRCodeGene()
{
Instance = new QRCodeGenerator();
}
public string Create(string text, QRCodeGenerator.ECCLevel value, int pixelsPerModule)
{
var qrCodeData = Instance.CreateQrCode(text, value);
var qrCode = new QRCode(qrCodeData);
var bitmap = qrCode.GetGraphic(pixelsPerModule);
// This line is the only modified by the provided in the code above.
bitmap.Save("C:\\"+text+".bmp", System.Drawing.Imaging.ImageFormat.Bmp);
//I return this string for testing. I guess If removed the text wouldn't work.
return ("Hello");
}
public void Dispose()
{
Instance.Dispose();
}
}
}
The code above generates the QRCode of anything I would send trough this function in access VBA:
Public Sub QR(Text As String)
Dim QRC As New QRCodeGene
Dim x As String
x = QRC.Create(Text, ECCLevel_Q, 5)
End Sub
After that I just load the picture generated with and access.image control source.
Thanks Florent B. for providing this code.

C# switch library using with program paremeters

I have a project with two class libraries.
I need to switch between them programatically, with application parameters, something like
if(arg == "a")
using LibraryA;
if(arg == "b")
using LibraryB;
namespace Project
{
public class MyClass
{
// my code here
}
}
If you want to build loose-couple application, i suggest you read more about Dependancy Injection pattern.
This is a nice article, desscribed how to build such design. (First 4 lessons)
This is quite a complex requirement and you'll have to bring together multiple patterns & practices to get through this. I'll try and link off to the relevant principles as I go along.
The first problem to tackle is aligning the two class libraries such that they have a common interface. This is necessary in order to make them interchangeable as you describe. Usually this would be as simple as creating an interface that both objects implement - but you mentioned that you only have control over one of the libraries. In that case you need to utilize the adapter pattern to coerce the library you don't have control over to implement your common interface.
Say we currently have these two classes in Library1.dll and Library2.dll (Library1.dll is the one we have control over)...
// in Library1.dll
public class Foo
{
public int DoSomething() { ... }
}
// In Library2.dll
public class Foo
{
public int DoSomething() { ... }
}
First we need to define our common interface. This should reside in a core/shared library...
// In Shared.dll
public interface IFoo
{
int DoSomething();
}
Now because we have control over library one, we can easily make it implement the common interface in the usual way...
// In Library1.dll
public class Foo : IFoo
{
public int DoSomething() { ... }
}
However because we don't have control over Library2.dll we'll need to create an adapter class. The purpose of this class is simply to implement the common interface, and all behaviour is delegated to the real Library2.Foo. In effect this allows us to make the Library2.Foo object implement our common interface.
// In Shared.dll
public class Foo2Adapter : IFoo()
{
private Library2.Foo _realFoo;
public Foo2Adapter()
{
_realFoo= new Library2.Foo();
}
public int DoSomething()
{
_realFoo.DoSomething();
}
}
Now we need to modify all of our client code to use the common interface rather than the objects directly. Where before you might have had something like this...
if(arg == "a")
using LibraryA;
if(arg == "b")
using LibraryB;
namespace Project
{
public class MyClass
{
public void Bar()
{
var foo = new Foo();
foo.DoSomething();
}
}
}
Now your code should only use the interface...
namespace Project
{
public class MyClass
{
public void Bar(IFoo foo)
{
foo.DoSomething();
}
}
}
Now we have a new problem, how do we know which version of IFoo to use? Is it Library1.Foo, or Shared.Foo2Wrapper?
You can use dependency injection to solve this problem. An inversion of control container will provide objects for you, and you can configure it to provide different kinds of objects based on certain conditions. Here's a psuedocode example using a sytax similar to that used by StructureMap (my personal favourite IoC container)...
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>();
Now when we call GetInstance<IFoo>() the IoC container will give us back either a Library1.Foo or a Shared.Foo2Wrapper depending on how it was configured by the command line. We now need to go through all the places in our client code where we previously had new Foo() and replace it with container.GetInstance<IFoo>().
I hope that gets you moving :)
Here's an example of how you can achieve what you're after.
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();
}
}
}
More info on mocks is available here: http://msdn.microsoft.com/en-us/library/ff650441.aspx
There's also a load of stuff at Channel9: http://channel9.msdn.com/search?term=test+driven+development
Alternatively you may be interested in this: http://msdn.microsoft.com/en-us/library/hh549175(v=vs.110).aspx. It allows you to hijack methods of existing objects and replace them with dummy methods. I've not yet played with this, but it looks promising.

Categories