C# IDisposable object for entire class - c#

The project that I'm working on at the moment uses an IDisposable object in every method in a class. It has started getting tedious re-typing the using block at the start of every method, and was wondering if there was a way to specify a disposable variable for use in every method of the class?
public static class ResourceItemRepository
{
public static ResourceItem GetById(int id)
{
using (var db = DataContextFactory.Create<TestDataContext>())
{
// Code goes here...
}
}
public static List<ResourceItem> GetInCateogry(int catId)
{
using (var db = DataContextFactory.Create<TestDataContext>())
{
// Code goes here...
}
}
public static ResourceItem.Type GetType(int id)
{
using (var db = DataContextFactory.Create<TestDataContext>())
{
// Code goes here...
}
}
}

No, there's nothing particularly geared towards this. You could write:
public static ResourceItem GetById(int id)
{
WithDataContext(db =>
{
// Code goes here...
});
}
// Other methods here, all using WithDataContext
// Now the only method with a using statement:
private static T WithDataContext<T>(Func<TestDataContext, T> function)
{
using (var db = DataContextFactory.Create<TestDataContext>())
{
return function(db);
}
}
I'm not sure that it would be particularly beneficial though.
(Note that I've had to change it from Action<TestDataContext> in my original version to Func<TestDataContext, T> as you want to be able to return values from your methods.)

Frankly, i'd keep the verbose code, but using a snippet instead of typing it all each time.
Either create your own snippet with a special tool or use text-replacement tools like Texter

Maybe a simple refactoring is the best that you can do without resorting to something like PostSharp:
public static class ResourceItemRepository {
public static ResourceItem GetById(int id) {
using (var db = CreateDataContext()) {
// Code goes here...
}
}
public static List<ResourceItem> GetInCateogry(int catId) {
using (var db = CreateDataContext()) {
// Code goes here...
}
}
public static ResourceItem.Type GetType(int id) {
using (var db = CreateDataContext()) {
// Code goes here...
}
}
private static TestDataContext CreateDataContext() {
return DataContextFactory.Create<TestDataContext>();
}
}

Related

Triggering DynamicData cache update using Reactive Subject

As a caveat I'm a novice with Rx (2 weeks) and have been experimenting with using Rx, RxUI and Roland Pheasant's DynamicData.
I have a service that initially loads data from local persistence and then, upon some user (or system) instruction will contact the server (TriggerServer in the example) to get additional or replacement data. The solution I've come up with uses a Subject and I've come across many a site discussing the pros/cons of using them. Although I understand the basics of hot/cold it's all based on reading rather than real world.
So, using the below as a simplified version, is this 'right' way of going about this problem or is there something I haven't properly understood somewhere?
NB: I'm not sure how important it is, but the actual code is taken from a Xamarin.Forms app, that uses RxUI, the user input being a ReactiveCommand.
Example:
using DynamicData;
using System;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
public class MyService : IDisposable
{
private CompositeDisposable _cleanup;
private Subject<Unit> _serverSubject = new Subject<Unit>();
public MyService()
{
var data = Initialise().Publish();
AllData = data.AsObservableCache();
_cleanup = new CompositeDisposable(AllData, data.Connect());
}
public IObservableCache<MyData, Guid> AllData { get; }
public void TriggerServer()
{
// This is what I'm not sure about...
_serverSubject.OnNext(Unit.Default);
}
private IObservable<IChangeSet<MyData, Guid>> Initialise()
{
return ObservableChangeSet.Create<MyData, Guid>(async cache =>
{
// inital load - is this okay?
cache.AddOrUpdate(await LoadLocalData());
// is this a valid way of doing this?
var sync = _serverSubject.Select(_ => GetDataFromServer())
.Subscribe(async task =>
{
var data = await task.ConfigureAwait(false);
cache.AddOrUpdate(data);
});
return new CompositeDisposable(sync);
}, d=> d.Id);
}
private IObservable<MyData> LoadLocalData()
{
return Observable.Timer(TimeSpan.FromSeconds(3)).Select(_ => new MyData("localdata"));
}
private async Task<MyData> GetDataFromServer()
{
await Task.Delay(2000).ConfigureAwait(true);
return new MyData("serverdata");
}
public void Dispose()
{
_cleanup?.Dispose();
}
}
public class MyData
{
public MyData(string value)
{
Value = value;
}
public Guid Id { get; } = Guid.NewGuid();
public string Value { get; set; }
}
And a simple Console app to run:
public static class TestProgram
{
public static void Main()
{
var service = new MyService();
service.AllData.Connect()
.Bind(out var myData)
.Subscribe(_=> Console.WriteLine("data in"), ()=> Console.WriteLine("COMPLETE"));
while (Continue())
{
Console.WriteLine("");
Console.WriteLine("");
Console.WriteLine($"Triggering Server Call, current data is: {string.Join(", ", myData.Select(x=> x.Value))}");
service.TriggerServer();
}
}
private static bool Continue()
{
Console.WriteLine("Press any key to call server, x to exit");
var key = Console.ReadKey();
return key.Key != ConsoleKey.X;
}
}
Looks very good for first try with Rx
I would suggest few changes:
1) Remove the Initialize() call from the constructor and make it a public method - helps a lot with unit tests and now you can await it if you need to
public static void Main()
{
var service = new MyService();
service.Initialize();
2) Add Throttle to you trigger - this fixes parallel calls to the server returning the same results
3) Don't do anything that can throw in Subscribe, use Do instead:
var sync = _serverSubject
.Throttle(Timespan.FromSeconds(0.5), RxApp.TaskPoolScheduler) // you can pass a scheduler via arguments, or use TestScheduler in unit tests to make time pass faster
.Do(async _ =>
{
var data = await GetDataFromServer().ConfigureAwait(false); // I just think this is more readable, your way was also correct
cache.AddOrUpdate(data);
})
// .Retry(); // or anything alese to handle failures
.Subscribe();
I'm putting what I've come to as my solution just in case there's others that find this while they're wandering the internets.
I ended up removing the Subjects all together and chaining together several SourceCache, so when one changed it pushed into the other and so on. I've removed some code for brevity:
public class MyService : IDisposable
{
private SourceCache<MyData, Guid> _localCache = new SourceCache<MyData, Guid>(x=> x.Id);
private SourceCache<MyData, Guid> _serverCache = new SourceCache<MyData, Guid>(x=> x.Id);
public MyService()
{
var localdata = _localCache.Connect();
var serverdata = _serverCache.Connect();
var alldata = localdata.Merge(serverdata);
AllData = alldata.AsObservableCache();
}
public IObservableCache<MyData, Guid> AllData { get; }
public IObservable<Unit> TriggerLocal()
{
return LoadLocalAsync().ToObservable();
}
public IObservable<Unit> TriggerServer()
{
return LoadServerAsync().ToObservable();
}
}
EDIT: I've changed this again to remove any chaining of caches - I just manage the one cache internally. Lesson is not to post too early.

Using the Decorator Pattern to Conditionally Replace Behaviour Instead of Extending

Initially I had this structure:
interface IFileBackup
{
void Backup();
}
class BackUpMechanism1 : IFileBackup
{
void Backup()
{
//Back it up
}
}
class BackUpMechanism2 : IFileBackup
{
void Backup()
{
//Back it up in another way
}
}
class Client
{
//Instantiation of both mechanisms
//
try
{
backUpMechanism1.Backup();
}
catch(Exception ex)
{
backupMechanism2.Backup();
}
}
I was told that this was not a very clean design and to redesign it using the decorator pattern. The client should not know about the two back up mechanisms but just call backup and then the first mechanism should try to back up the file and if that fails then use mechanism 2. However I don't understand how to use the decorator pattern because from my understanding it extends functionality but doesn't replace functionality - which is what I want... How do I archive that? I have tried the following:
interface IFileBackup
{
void Backup();
}
class BackupMechanism1 : IFileBackup
{
public void Backup()
{
try
{
Console.WriteLine("Trying to back up to the cloud...");
throw new Exception();
}
catch(Exception ex)
{
Console.WriteLine("Oops that failed. We need to back up locally instead...");
}
}
}
class BackupMechanism2 : IFileBackup
{
IFileBackup _fileBackup;
public BackupMechanism2(IFileBackup fileBackup)
{
_filebackup = fileBackup;
}
public void Backup()
{
//All examples I have seen does this. But doesn't make sense in my case?
_fileBackup.Backup();
Console.WriteLine("Backing up locally");
}
}
//The client does not care about how the backup is done
class Client
{
static void Main()
{
//This is not right, but not sure what I should do in the client.
BackupMechanism2 localBackup = new BackupMechanism2(new BackupMechanism1());
localBackup.Backup();
Console.Read();
}
}
So essentially what I want to achieve is to have two backup mechanisms. Have the client just say backup I don't care how. Let the first mechanism try it's backup method if that fails then try the second method. I'm trying to use the decorator pattern to extend(replace) the backup behaviour of the first mechanism if it fails. I'm struggling to come up with a design that makes sense.
A very clean approach of implementing this would be adding a composite IFileBackup taking an array of IFileBackup objects, and trying them one by one until a working solution is found:
class CompositeBackup {
private readonly IFileBackup[] chain;
public CompositeBackup(params IFileBackup[] chain) {
this.chain = chain.ToArray();
}
public void Backup() {
foreach (var backup in chain) {
try {
backup.Backup();
return;
} catch {
continue;
}
}
throw new InvalidOperationException();
}
}
Now the client simply does this:
IFileBackup backup = new CompositeBackup(
new BackupMechanism1()
, new BackupMechanism2()
);
backup.Backup();
If you later decide to add BackupMechanism3 and BackupMechanism4, the user would need to add another object to the chain of backups. The rest of the code would remain unchanged. In addition, backup mechanisms themselves would remain unaware of other mechanisms' existence, which also simplifies the code.
The decorator pattern, in this case, can be used to provide fallback implementations. You can find plenty of obvious examples in the .Net streams implementation.
So with that in mind, your code should look something like this:
class abstract BaseFileBackup
{
internal BaseFileBackup Fallback;
internal BaseFileBackup(BaseFileBackup fallback) { Fallback = fallback; }
internal BaseFileBackup() { }
internal abstract void DoBackupWork();
internal void Backup()
{
try { DoBackupWork(); }
catch { if(Fallback != null) Fallback.Backup(); else throw; }
}
}
class BackUpMechanism1 : BaseFileBackup
{
internal BackUpMechanism1 (BaseFileBackup fallback): base(fallback) {}
internal BackUpMechanism1 (): base() {}
internal void DoBackupWork()
{
//Back it up
}
}
class BackUpMechanism2 : BaseFileBackup
{
internal BackUpMechanism2 (BaseFileBackup fallback): base(fallback) {}
internal BackUpMechanism2 (): base() {}
internal void DoBackupWork()
{
//Back it up in another way
}
}
// and to call it
class Client
{
static void Main()=>
new BackupMechanism2(new BackupMechanism1()).Backup();
}
Decorator Pattern is the WRONG choice in this scenario.
The problem that you are dealing with here is
under condition x call one method
under condition y call a different method
...
This is the precondition for the Strategy Pattern, and your initial solution was quite close to that. The problem in my mind is that you are using an Exception to determine the program flow, which is a BAD thing to do: exceptions cost stack space, and they should only be thrown under EXCEPTIONAL circumstances. Whereas in your case, it is expected that a given strategy will not work
IFileBackupStrategy
{
bool Backup(File fileToBackup);
}
IFileBackupContext
{
File ForBackup { set; }
bool Backup();
}
class CloudBackUp : IFileBackupStrategy
{
private bool _success;
public bool Backup(File fileToBackup)
{
// code to do backup omitted
// it will set the value of _success to false if it was unsuccessful
return _success;
}
}
class LocalBackUp : IFileBackupStrategy
{
private bool _success;
public bool Backup(File fileToBackup)
{
// code to do backup omitted
// it will set the value of _success to false if it was unsuccessful
return _success;
}
}
public class FileBackupContext : IFileBackupContext
{
private IEnumerable<IFileBackupStrategy> _backupStrategies
public Context(IEnumerable<IFileBackupStrategy> backupStrategies)
=> _backupStrategies = backupStrategies;
public File ForBackup { set; private get; }
public bool Backup()
{
bool successFlag;
foreach(var strategy in _backupStrategies)
{
successFlag = strategy.Backup(ForBackup);
if(successFlag) break;
}
return successFlag;
}
}
In this case, all that the client needs to be aware of is the IFileBackupContext, and not the strategy employed to do the saving.
public class MyBackupClient
{
private IFileBackupContext _context;
public MyBackupClient(IFileBackupContext context) => _context = context;
void SomeMethodThatInvokesBackingUp()
{
_context.ForBackup = new File(/* */);
if(!_context.Backup())
{
Console.WriteLine("Failed to backup the file");
}
}
}
The beauty of this design is that you can add more IFileBackupStrategy implementations, register them with your DI Container and voila they are instantly available to the client without a single code change or the need for re-compilation (though that will ultimately depend upon how you are populating your DI Container)
The decorator pattern is a method of adhering to the O principle in SOLID: which is
Open for extension and closed for modification
This means that you would use the decorator pattern to decorate an existing class, one that should not be changed and yet does not exhibit the behaviour required. The clue is in the name of the pattern: Decorator adds something, it does not change anything.
The Decorator Pattern is a Structural Pattern, whereas the Strategy Pattern, and what you are looking for, is a Behavioural Pattern
This example can be extended of course to report back the strategy which was ultimately employed, and also (if required) any reasoning for why alternate strategies were not.
Edited: in response to Blindy's comment below. Here is the paradigm for the decorator pattern, which should demonstrate how it is not the correct pattern for this problem:
class Image
{
void Render() { /* */ }
}
class FramedImage : Image
{
private Image _originalImage;
public FramedImage(Image original) => _originalImage = original;
new public void Render()
{
/* code to render a frame */
_originalImage.Render();
}
}
Image originalImage = new Image();
Image framedImage = new FramedImage(originalImage);
Image toRender = originalImage;
toRender.Render() // Renders the original image
toRender = framedImage;
toRender.Render(); // Renders the original image in a frame
It should be observed that there is no need to assign each Image to the toRender variable, that is done solely to demonstrate that a decorator is a decorated.
As you can see from this example, the decorator pattern adds behaviour, and it also invokes the decorated item's behaviour.
Edited: Further to the question posed by DSF below. Here is the full listing for a console app demonstrating how to achieve this using Unity 5.8.6
The code takes advantage of the new Tuple from C# 7.0.
I've just used some random number generation to determine whether or not each strategy implementation succeeds in performing its task.
using System;
using System.Collections.Generic;
using System.IO;
using Unity;
using Unity.Injection;
namespace StrategyPattern
{
public interface IFileBackupContext
{
FileStream ForBackup { set; }
(bool success, string strategy) Backup();
}
public interface IFileBackupStrategy
{
(bool success, string name) Backup(FileStream fileToBackup);
}
internal class LocalBackUp : IFileBackupStrategy
{
private bool _success = false;
public (bool success, string name) Backup(FileStream fileToBackup)
{
// code to do backup omitted
var random = new Random(DateTime.Now.Millisecond);
_success = (random.Next() % 3) == 0;
if(_success) fileToBackup.Close();
// it will set the value of _success to false if it was unsuccessful
return (_success, "LocalBackUp");
}
}
internal class CloudBackUp : IFileBackupStrategy
{
private bool _success = false;
public (bool success, string name) Backup(FileStream fileToBackup)
{
// code to do backup omitted
var random = new Random(DateTime.Now.Millisecond);
_success = (random.Next() % 3) == 0;
if (_success) fileToBackup.Close();
// it will set the value of _success to false if it was unsuccessful
fileToBackup.Close();
return (_success, "CloudBackUp");
}
}
public class FileBackupContext : IFileBackupContext
{
private readonly IEnumerable<IFileBackupStrategy> _backupStrategies;
public FileBackupContext(IEnumerable<IFileBackupStrategy> backupStrategies)
=> _backupStrategies = backupStrategies;
public FileStream ForBackup { set; private get; }
public (bool success, string strategy) Backup()
{
foreach (var strategy in _backupStrategies)
{
var (success, name) = strategy.Backup(ForBackup);
if (success) return (true, name);
}
return (false, "");
}
}
public class MyBackupClient
{
private IFileBackupContext _context;
public MyBackupClient(IFileBackupContext context) => _context = context;
public void BackgUpMyFile()
{
_context.ForBackup = new FileStream("d:\\myfile", FileMode.OpenOrCreate);
(bool success, string strategy) = _context.Backup();
if (!success)
{
Console.WriteLine("Failed to backup the file");
return;
}
Console.WriteLine($"File backed up using [{strategy}] strategy");
}
}
public class Bootstrap
{
private readonly IUnityContainer _container;
public Bootstrap()
{
_container = new UnityContainer();
_container.RegisterType<IFileBackupContext, FileBackupContext>();
_container.RegisterType<IFileBackupStrategy, LocalBackUp>("local");
_container.RegisterType<IFileBackupStrategy, CloudBackUp>("cloud");
_container.RegisterType<MyBackupClient>();
_container.RegisterType<Func<IEnumerable<IFileBackupStrategy>>>(new InjectionFactory(c =>
new Func<IEnumerable<IFileBackupStrategy>>(() =>
new[]
{
c.Resolve<IFileBackupStrategy>("local"),
c.Resolve<IFileBackupStrategy>("cloud")
}
)));
}
public MyBackupClient GetClient() => _container.Resolve<MyBackupClient>();
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press ESC to quit ...");
Console.WriteLine("Press any other key to try again.");
Console.WriteLine();
var client = new Bootstrap().GetClient();
do
{
client.BackgUpMyFile();
} while (Console.ReadKey().Key != ConsoleKey.Escape);
}
}
}

Conditional type aliasing

I would like to be able to present a choice to the user - whether to use 16bit indices (in OpenGL) or 32bit indices. In C++, I'd probably just create an alias for int or short, but I don't seem to have the option in C#. Basically what I'm going for can be summed up in the class below:
using System;
namespace Something
{
public class Conditional
{
public Conditional(Boolean is16Bit)
{
if (is16Bit)
{
SOMETYPE is Int16
}
else
{
SOMETYPE is Int32
}
}
private List<SOMETYPE> _something;
}
}
The aliasing (if it can be done) would be vastly better - I just don't want to force anyone using this code into writing #define statements, is that possible?
Thanks
Seems like you could use a generic for this:
namespace Something
{
public class Conditional<T>
{
private List<T> _something = new List<T>();
private Conditional()
{
// prevents instantiation except through Create method
}
public Conditional<T> Create()
{
// here check if T is int or short
// if it's not, then throw an exception
return new Conditional<T>();
}
}
}
And to create one:
if (is16Bit)
return Conditional<short>.Create();
else
return Conditional<int>.Create();
You can use an interface and a factory, something like this:
public interface IConditional
{
void AddIndex(int i);
}
private class Conditional16 : IConditional
{
List<Int16> _list = new List<Int16>();
public void AddIndex(int i)
{
_list.Add((short)i);
}
}
private class Conditional32 : IConditional
{
List<Int32> _list = new List<Int32>();
public void AddIndex(int i)
{
_list.Add(i);
}
}
public static class ConditionalFactory
{
public static IConditional Create(bool is16Bit)
{
if (is16Bit)
{
return new Conditional16();
}
else
{
return new Conditional32();
}
}
}
Your code (and callers of it) can do everything against IConditional without caring which of the concrete representations it is.

Strongly typed metadata in MEF2 (System.Composition)

I'm using the System.Composition namespace from the MEF for web and Windows Store apps NuGet package in a new ASP.NET MVC4 project.
I've read that in MEF2 you no longer use Lazy<IExtension, IExtensionMetadata>, but now you must provide a concrete type for the metadata view (and possibly use ExportFactory<> instead of Lazy<> ?).
However, I can't find any examples of how this should all work - just a few mentions of using a concrete type instead of an interface.
I've tried a few things, but keep getting the following error - "Export metadata for 'AccountID' is missing and no default value was supplied".
My code...
Creating the container (in Global.asax or App_Start folder):
// Get assemblies that will be providing imports and exports
var assemblies = GetAssemblies();
// Get conventions that will be used to find imports and exports
var conventions = GetConventions();
var container = new ContainerConfiguration().WithAssemblies(assemblies, conventions).CreateContainer();
// Create and apply a MefControllerFactory so controllers can be composed
ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));
GetConventions() method:
private static ConventionBuilder GetConventions()
{
var conventionBuilder = new ConventionBuilder();
conventionBuilder.ForTypesDerivedFrom<IController>().Export();
conventionBuilder.ForTypesDerivedFrom<IExtension>().Export<IExtension>();
conventionBuilder.ForTypesMatching(t => t.Namespace != null && t.Namespace.EndsWith(".Parts")).Export().ExportInterfaces();
return conventionBuilder;
}
IExtension.cs:
public interface IExtension
{
void DoWork();
}
ExtensionMetadata.cs:
public class ExtensionMetadata
{
public int AccountID { get; set; }
}
ExtensionA.cs (same as ExtensionB.cs):
public void DoWork()
{
System.Diagnostics.Debug.WriteLine("ExtensionA doing work..");
}
ExtensionManager.cs:
public class ExtensionManager
{
private IEnumerable<ExportFactory<IExtension, ExtensionMetadata>> _extensions;
public ExtensionManager(IEnumerable<ExportFactory<IExtension, ExtensionMetadata>> extensions)
{
_extensions = extensions;
}
public void DoWork(int accountID)
{
foreach (var extension in _extensions)
{
if (extension.Metadata.AccountID == accountID)
{
extension.DoWork();
}
}
}
}
I think I'm missing something quite major here. Basically I want to lazily import all Extensions, check their metadata and if a condition is fulfilled have that extension do something.
Would really appreciate your feedback or any links to sample code / tutorials that cover my scenario.
Many thanks!
I think I've worked it out after reading this SO question.
I created a Metadata Attribute:
[MetadataAttribute]
public class ExtensionMetadataAttribute : ExportAttribute, IExtensionMetadata
{
public int AccountID { get; set; }
public ExtensionMetadataAttribute(int accountID) : base(typeof (IExtension))
{
AccountID = accountID;
}
}
Then modified ExtensionA.cs:
[ExtensionMetadata(1)]
public class ExtensionA : IExtension
{
public void DoWork()
{
System.Diagnostics.Debug.WriteLine("ExtensionA doing work..");
}
}
And now ExtensionManager.cs looks like this:
public class ExtensionManager : IExtensionManager
{
private readonly IEnumerable<ExportFactory<IExtension, ExtensionMetadata>> _extensions;
public ExtensionManager(IEnumerable<ExportFactory<IExtension, ExtensionMetadata>> extensions)
{
_extensions = extensions;
}
public void DoWork(int accountID)
{
foreach (var extension in _extensions)
{
if (extension.Metadata.AccountID == accountID)
{
using (var foo = extension.CreateExport())
{
foo.Value.DoWork();
}
}
}
}
}
This seems to do the trick, but I would still be interested in any feedback re best practices, performance issues etc.
Thanks!

EF4 context creation in one method

I have many methods like this:
public IEnumerable<Director> GetAllDirectors()
{
using (var dbContext = new BodModelContainer())
{
return dbContext.Members.OfType<Director>().ToList();
}
}
..or this..
public Member GetMemberById(int memberId)
{
using(var dbContext = new BodModelContainer())
{
return dbContext.Members.Find(new[] {memberId});
}
}
or that:
public SomeType GetOrDoSomethingWithDbBySomethingElse(T1 t1var, T2, T2 var, ...)
{
using(var dbContext = new BodModelContainer())
{
return dbContext.SomeType.DoSomething();
}
}
So I wanna reorganize all of these methods something like:
// create db context here
public void InDb(Func<BodModelContainer, out SomeGenericType???> workingWithDb)
{
using(var dbContext = new BodModelContainer())
{
workingWithDb(dbContext);
}
}
// using it like
public Member GetMemberById(int memberId)
{
InDb((dbContext) =>
{
return dbContext.Members.Find(new[] { memberId });
});
}
Question: How to make such generic InDb method, what is SomeGenericType???
The actual problem it looks like you're describing is the fact that you can't figure out how to set the return type of the Func<>. To be able to make this generic you'll need to make InDb require a generic type as well.
public TRet InDb<TRet>(Func<BodModelContainer, TRet> workingWithDb) {
TRet ret = default(TRet);
using (var dbContext = new BodModelContainer()) {
ret = workingWithDb(dbContext);
}
return ret;
}
public Member GetMemberById(int memberId) {
return InDb(dbContext => { return dbContext.Members.Find(new[] { memberId }); });
}
Should work (all the code here is untested), or using anonymous methods you could have a local variable and make .Net do all the nasty work.
public void InDb(Action<BodModelContainer> workingWithDb) {
using (var dbContext = new BodModelContainer()) {
workingWithDb(dbContext);
}
}
public Member GetMemberById(int memberId) {
Member member;
InDb(dbContext => { member = dbContext.Members.Find(new[] { memberId }); });
return member;
}
Of course, this all being said, I don't know if this level of redirection/abstraction is useful - you're making it slightly more complicated with little perceptible gain (if any). Unless there is a lot of work setting up and tearing down the dbContext used in InDb I don't think it is very helpful.

Categories

Resources