Is it possible to limit object creation to methods of specific class?
For exemple: I have a class Transaction, and I would like to limit it object creation to methods of any class that inherits from AbstractService or IService:
Allowed Scenario:
public class ServiceA : AbstractService (or IService)
{
public void MethodA()
{
var transaction = new Transaction();
}
public void MethodB()
{
var transaction = new Transaction();
}
}
Prohibited Scenario:
public class ServiceB
{
public void MethodA()
{
var transaction = new Transaction(); // cannot create
}
public void MethodB()
{
var transaction = new Transaction(); // cannot create
}
}
There is a access modifier or something else that I can mount that scenarios?
There is a access modifier or something else that I can mount that scenarios?
Yes there is something else that can "mount" that scenario, but it's a lot of work and abstraction for, in my opinion, very little reward. This requires returning an interface of the Transaction, not a concrete type. (I'm pretty sure this works, I haven't compiled it however).
public abstract class AbstractService
{
}
public interface IService
{
}
public interface ITransaction
{
}
public static class TransactionFactory
{
// created them as extensions, but you could remove *this*
public static ITransaction CreateTransaction(this AbstractService instance)
{
return new Transaction ();
}
public static ITransaction CreateTransaction(this IService instance)
{
return new Transaction ();
}
private class Transaction : ITransaction
{
public Transaction ()
{
}
}
}
As a side note, someone technically could pass in null, so it would be best to do additional checking of the method parameters (however, that would be a runtime issue instead of a compile time issue).
If you wanted compile time checking I think you could do...
public interface ITransactionFactory { }
public abstract class AbstractService : ITransactionFactory { }
public interface IService : ITransactionFactory { }
public static class TransactionFactory<T>
where T : ITransactionFactory
{
public static ITransaction CreateTransaction(this T instance)
{
return new Transaction ();
}
// ....
Not quite sure if the second one works
The short answer is no, there is no access modifier which says "This object can only be constructed from a class which implements a specific interface".
You could code your way round this limitation, but its far from clean/foolproof.
public class Transaction
{
private Transaction(){} // private important!
public static Transaction Create(object creator)
{
if(creator is IService)
return new Transaction();
throw new InvalidOperationException();
}
}
public class ServiceA : IService
{
public void MethodA()
{
var transaction = Transaction.Create(this); // works
}
}
public class ServiceB
{
public void MethodA()
{
var transaction = Transaction.Create(this); // fails
}
}
It should be obvious how easily circumventable the above is. I suspect you have an XY Problem and you think this was the way to solve it.
Maybe I'm misunderstanding what you're trying to do, but it seems like this should do the trick:
public abstract class AbstractService : IService
{
protected class Transaction
{
}
}
public class ServiceA : AbstractService
{
public void MethodA()
{
var transaction = new Transaction();
}
public void MethodB()
{
var transaction = new Transaction();
}
}
public class ServiceB
{
public void MethodA()
{
var transaction = new Transaction(); // cannot create
}
public void MethodB()
{
var transaction = new Transaction(); // cannot create
}
}
internal interface IService
{
}
If you want anyone else to be able to use the Transaction, you'll need to have it implement some public interface or inherit it from another public class, but you can now ensure that no one else can create a Transaction object.
Related
Good day. I have a problem of understanding the Dependency Injection.
So what exactly do I need is to have access from child objects to parent objects.
For example, I have my MainProgram object. This object creates another object, another object create 3-d objects and so on. Let's stop on child object #5
This child needs to have a reference to object #1.
I don't understand how to do this in a better way. But then I started to search and find something called Dependency Injection.
I really hope that this thing is the right answer for my issue (If not, please tell).
So here in my problem and example.
I'm trying to create a WEB API for one of my services. Using ASP .NET Core 6
First, I created a simple class that will be MainProgram, when Server will receive POST request with needed data, it will launch some working in multi-threading.
public class MainProgram
{
public int MaxThreads { get; set; }
public int OrderCounter { get; set; }
public AdjustableSemaphore Semaphore { get; set; }
public MainProgram(int maxThreads)
{
MaxThreads = maxThreads;
Semaphore = new AdjustableSemaphore(MaxThreads);
}
public async Task StartOperation(IApiOperation operation)
{
try
{
operation.Prepare();
operation.Start();
while (!operation.IsReady())
{
await Task.Delay(500);
}
operation.Finish();
}
catch (Exception e)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(e.Message);
Console.ResetColor();
}
}
public string OperationStatus(IApiOperation operation)
{
return operation.ShowDetails();
}
}
Then I added this class to Program.cs for Dependency.
builder.Services.AddSingleton(program => new MainProgram(1000));
I made a Constructor for my Controller as it was in the example I read and all worked great.
Controller create instance of MainProgram by its own.
[ApiController]
[Route("/")]
public class ApiController : ControllerBase
{
private MainProgram _mainProgram;
public ApiController(MainProgram mainProgram)
{
_mainProgram = mainProgram;
}
[HttpPost]
[Route("test")]
public string Get()
{
TestOperation to = new TestOperation(_mainProgram);
new Thread(() =>
{
var project = _mainProgram.StartOperation(to);
}).Start();
return $"Started task #{to.Id}";
}
}
The problems that I have are in this line
TestOperation to = new TestOperation(_mainProgram);
This TestOperation also has a Dependency from MainProgram. I understand that I can pass my private _mainProgram in it.
But let's pretend that TestOperation also has a child, and this child also has a child, and only the third one needs a link to MainProgram.
I thought that's where Dependency Injection helps.
Main Question is
How can I create objects that have a constructor with dependency for MainProgram,
If I cannot write new TestOperation(WITHOUT ATTRIBUTE)? It will be a syntax error.
I think you'd avoid the cycle of dependency;
If you couldn't avoid it ,you could try to inject the IServiceProvider into your services,and get the target service with provider.GetService() method,and you could try to create a Parameterservice or Static class to hold the parameter you need,
I tried as below :
Services:
interface IA {int methodA();}
interface IB { int methodB(); }
interface IC { int methodC(); }
interface IParameterService { }
public class ParameterService: IParameterService
{
public int APara;
public int BPara;
public ParameterService(int para)
{
APara = para+1;
}
}
public class A : IA
{
private readonly IServiceProvider _provider;
private readonly int Id;
public A(IServiceProvider provider)
{
_provider = provider;
Id = (provider.GetService(typeof(IParameterService)) as ParameterService).APara;
}
public int methodA()
{
return Id+1;
}
}
public class B : IB
{
private readonly IServiceProvider _provider;
public B(IServiceProvider provider)
{
_provider = provider;
}
public int methodB()
{
return (_provider.GetService(typeof(IA)) as A).methodA();
}
}
public class C : IC
{
private readonly IServiceProvider _provider;
public C(IServiceProvider provider)
{
_provider = provider;
}
public int methodC()
{
return (_provider.GetService(typeof(IB)) as B).methodB();
}
}
In startup:
services.AddTransient<IParameterService>(x => new ParameterService(1));
services.AddTransient<IA,A>();
services.AddTransient<IB,B>();
services.AddTransient<IC, C>();
in controller:
private readonly A _A;
private readonly C _C;
public SomeController(IServiceProvider provider)
{
_A = (A)provider.GetService(typeof(IA));
_C=(C)provider.GetService(typeof(IC));
}
Result:
Lets say I want to use, for example, a new DbContext object whenever a method is called in a class but without getting it by a parameter. Like so
class MyClass {
public virtual void MethodOne() {
// Having automatically a new instance of DbContext
}
public virtual void MethodTwo() {
// Also having automatically a new instance of DbContext
}
}
What I was really hoping for was a DI way of doing this. Like public void Method(IMyWayOfContext context).
class MyClass {
public virtual void MethodOne(IMyWayOfContext context)) {
}
public virtual void MethodTwo(IMyWayOfContext context) {
}
}
Other classes inheriting from this class must be provided with a new instance of dbcontext. That's why I don't want to create a new instance inside of the function
You could do something like this (generic interface, plus a wrapper with multiple constraints):
class DBContext{ }
interface IDoesMethods<TContext> where TContext : new()
{
void MethodOne(TContext context = default(TContext));
void MethodTwo(TContext context = default(TContext));
}
class MyClass : IDoesMethods<DBContext>
{
public void MethodOne(DBContext context)
{
}
public void MethodTwo(DBContext context)
{
}
}
class MyContextWrapper<TClass, TContext> : IDoesMethods<TContext> where TContext : new() where TClass : IDoesMethods<TContext>, new()
{
public void MethodOne(TContext context = default(TContext))
{
instance.MethodOne(new TContext());
}
public void MethodTwo(TContext context = default(TContext))
{
instance.MethodTwo(new TContext());
}
private TClass instance = new TClass();
}
class Program
{
static void Main(string[] args)
{
var wrapper = new MyContextWrapper<MyClass, DBContext>();
wrapper.MethodOne();
wrapper.MethodTwo();
}
}
Make a property with only getter that will return new instance every time
protected DbContext MyDBContext
{
get
{
return new DbContext();
}
}
EDIT: If you want some kind of dependency injection you can make your class generic and pass to instance of the class what type of context you want
class MyClass<T> {
protected DbContext MyDBContext
{
get
{
return Activator.CreateInstance<T>();
}
}
public void MethodOne() {
// Having automatically a new instance of DbContext
}
public void MethodTwo() {
// Also having automatically a new instance of DbContext
}
}
Your simple solution can work this way:
class MyClass {
protected DbContext InternalContext {
return new DbContext();
}
public virtual void MethodOne(DbContext dc = null) {
if(dc == null)
dc = InternalContext;
// do your work
}
public virtual void MethodTwo(DbContext dc = nnull) {
if(dc == null)
dc = InternalContext;
// do your work
}
}
In that case, you have to take care of disposing InternalContext
While answer here looks valid, they don't seem to fulfill perfectly your requirement of having a solution that rely on DI.
DI in it's simplest expression is most of the time achieve with Constructor Injection.
Your design was already good and DI ready.
Indeed, asking for dependencies via the constructor is good.
It is at the composition root of your application that you need to decide what implementation you need to pass.
Using a DI library can help (but it is not required to enable DI).
With your actual class design:
class MyClass {
public virtual void MethodOne(IMyWayOfContextFactory contextFactory)) {
using(var context = contextFactory.Create()){
//play with context
}
}
public virtual void MethodTwo(IMyWayOfContextFactory contextFactory) {
using(var context = contextFactory.Create()){
//play with context
}
}
}
public ContextFactory : IMyWayOfContextFactory {
IMyWayOfContext Create(){
return new MyWayOfContext();
}
}
Without a factory and with a DI container like SimpleInjector, you could have:
class MyClass {
public virtual void MethodOne(IMyWayOfContext context)) {
//play with context
}
public virtual void MethodTwo(IMyWayOfContext context) {
//play with context
}
}
And register your component once at the composition root with configurable Lifestyle management:
container.Register<IMyWayOfContext, MyWayOfContext>(Lifestyle.Transient);
The latter approach is simpler if you want to configure when to inject what instance of your context. Indeed, such configuration is built in an DI Container library. For instance, see: Lifestyle of component with SimpleInjector
I have the following code:
public interface IMyActionFactory
{
AbstractAction<T> CreateAction<T>(MyActionParamBase paramBase = null)
where T : MyActionParamBase;
}
public sealed class MergeActionParam : MyActionParamBase
{
}
public class MergeTest
{
private readonly IMyActionFactory _actionFactory = new DefaultMyActionFactory();
[Theory]
[PropertyData("MergeWorksData")]
public void MergeWorks(/*params here*/)
{
var param = new MergeActionParam();
// populate param here
var sut = _actionFactory.CreateAction<MergeActionParam>(param);
sut.DoAction();
}
}
I am getting an error
"..Error 10 Using the generic type 'IMyActionFactory' requires 1
type arguments..."
Why does the compiler expect a type to be passed to my IMyActionFactory, since I have declared the interface without a T? As far as the method is concerned its the only one to expect the type. Am I missing something here?
How can I make it work without redefining the interface signature?
EDIT:
Feeling a bit embarassed here, because the quick code I put down and ran seperately in a standalone online c# compiler doesnt give any compilation errors. However, going back to my original solution (tens of projects altogether) the error is still there.. Maybe has something to do with the XUnit ?..not sure
public interface IMyActionFactory
{
AbstractAction<T> CreateAction<T>(MyActionParamBase paramBase = null)
where T : MyActionParamBase;
}
public interface IAction
{
void DoAction();
}
public abstract class AbstractAction<T> : IAction
where T : MyActionParamBase
{
public void DoAction()
{
}
}
public class MyActionParamBase
{
public MyActionParamBase()
{
}
}
public sealed class MergeActionParam : MyActionParamBase
{
}
public class DefaultMyActionFactory : IMyActionFactory
{
public AbstractAction<T> CreateAction<T>(MyActionParamBase paramBase = null) where T : MyActionParamBase
{
return null;
}
}
public class MergeTest
{
private readonly IMyActionFactory _actionFactory = new DefaultMyActionFactory();
public void MergeWorks(/*params here*/)
{
var param = new MergeActionParam();
// populate param here
var sut = _actionFactory.CreateAction<MergeActionParam>(param);
sut.DoAction();
}
}
I've Generic Repository Class like this:
public class Repository : IDisposable
{
public static DataContext context { get; set; }
public static void Insert<T>(T item) where T : class
{
try
{
var table = context.GetTable<T>();
table.InsertOnSubmit(item);
context.SubmitChanges();
}
catch (Exception)
{
throw;
}
}
public void Dispose()
{
context.Dispose();
}
}
Above one is my Generic Class for Inserting Entity using Linq to sql.
I've total 10 entities in my datacontext and i'm writing 10 Insert methods like this(Example i'm providing 3 methods).
public void AddStudent(Student st)
{
Repository.Insert<Student>(st);
}
public void AddEmployee(Employee emp)
{
Repository.Insert<Employee>(emp);
}
public void AddStudent(Product prod)
{
Repository.Insert<Product>(prod);
}
like this I've 10 methods. is there a way to optimize this code. like this
I want to create a class with Add method and i'll use this add method entire my app where ever it is required.
public class Class1
{
public void Add(Table table)
{
Repository.Insert<Table>(table);
}
}
I want to use like this Class1 cls1 = new Class1(); cls1.Add(StudentObject);
can please suggest the way to implement class.
You could define a generic class rather than just a method:
public class Repository<T> : IDisposable
{
public static DataContext context { get; set; }
public static void Insert(T item)
{
var table = context.GetTable<T>();
table.InsertOnSubmit(item);
context.SubmitChanges();
}
public void Dispose()
{
context.Dispose();
}
}
And you then get the following, rather than all the additional methods:
var repo = new Repository<Product>();
repo.Insert(aProduct);
I have two derived classes (Sale and ServiceCharge). Both are Transactions. If I have a BusinessService, I want to create a ServiceCharge for it. If I pass a Product, I want to instantiate Sale.
Here's my idea.
private void CreateInstance(object element)
{
Transaction transaction;
if (element.GetType() == typeof(BussinessService))
{
transaction = new ServiceCharge((BussinessService)element))
}
else
{
transaction = new Sale((Product)element);
}
{
Could you tell me a more elegant way? I would know how to use generics with only a single constructor
private void CreateInstance<T>(T element)
{
Transaction transaction = new Transaction((T)element);
}
But I don't know how to work out with the first case.
Just a plain interface would also work in this case:
interface ITransactionable
{
Transaction CreateTransaction();
}
class BusinessService : ITransactionable
{
public Transaction CreateTransaction() { return new ServiceCharge( this ); }
}
class Product : ITransactionable
{
public Transaction CreateTransaction() { return new Sale( this ); }
}
private void CreateInstance(ITransactionable element)
{
Transaction transaction = element.CreateTransaction();
...
}
Define a generic interface like this:
public interface ITransactionable<T>
where T : Transaction
{
T CreateTransaction();
}
And decorate your BussinessService and Product as:
public class BussinessService :
ITransactionable<ServiceCharge>
{
public T CreateTransaction()
{
return new ServiceCharge(this);
}
}
public class Product :
ITransactionable<Sale>
{
public T CreateTransaction()
{
return new Sale(this);
}
}
Now your generic method can be defined as:
private void CreateInstance<T>(ITransactionable<T> element)
{
Transaction transaction = element.CreateTransaction();
...
}
Just create two different methods:
private void CreateInstance(Product product)
{
Transaction transaction = new Sale(product);
}
private void CreateInstance(BusinessService service)
{
Transaction transaction = new ServiceCharge(service);
}
The compiler will know what method you called depending on the type of the parameter you use.
BusinessService and Product should be polymorphic in some way, probably by sharing a interface, somthing like
interface IChargable<out T> where T : Transaction
{
Transaction Charge();
}
The interface implemented thus,
class BusinessService : IChargable<ServiceCharge>
{
public ServiceCharge Charge()
{
return new ServiceCharge(...
}
}
class Product : IChargable<Sale>
{
public Sale Charge()
{
return new Sale(...
}
}
which means some code like this would work
var chargables = new IChargable<Transaction>[]
{
new BusinessService(),
new Product()
};
var transactions = chargables.Select(c => c.Charge());