๋๋ง์ MVVM ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ง๋ค๊ธฐ #1 IOC Container
MVVM Toolkit๊ณผ Prism์ ์ฅ์ ์ ์๊ธฐ ์ํ ๊ณ ๋๊ณผ ์ญ๊ฒฝ ใ
ConvMVVM ์์ค์ฝ๋
๋ธ๋ก๊ทธ ๊ธ ๋งํฌ
๋๊ธฐ
์ ๋ ์ฌ์ค C#๊ฐ๋ฐ ๊ฒฝ๋ ฅ์ด ์งง์ต๋๋ค.
๊ทธ๋๋ ์์ฆ ์ฌ๋ฏธ๊ฐ ๋ค๋ ค์ ์ด๊ฒ์ ๊ฒ ๋ณด๊ณ ์๋๋ฐ ๋ฌธ๋ ๋๋ ์๊ฐ์ดโฆ ์ด๋ฐ๊ฒ๋ค์ ์ฐ๋ ๊ฒ๋ ์ค์ํ์ง๋ง ์ด๋ฐ ๊ธฐ๋ฅ๋ค์ ๋ด๊ฐ ๊ตฌํ์ ๋ชปํ๋ฉด ๋ด๊ฒ์ด ์๋๋ผ๋ ์๊ฐ์ด ๋ค๋๊ตฐ์
๋ฆ์์ง๋ง ์กฐ๊ธ์ฉ ๋๋ง์ MVVM๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ง๋ค์ด๋ณด๋ฉด์ ๊ธฐํ๊ฐ ๋๋ค๋ฉด ๋ค๋ฅธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์๋ ์๋ ์๋น์ค๋ ๊ฐ์ด๊ฐ์ ๊ธฐ๋ฅ์ ๋ฃ์ด๋ณด๊ณ ์ ํฉ๋๋ค.
์ฃผ๋ณ ์ง์ธ๋ถ๋ค ๋ง์ ๋ค์ด๋ณด๋ฉด IOC์ปจํ ์ด๋ ์ข ๋ฅ๋ ๋ค์ํ๋ค๊ณ ๋ค์๋๋ฐ ๋ง์ ๊ฒ๋ค์ ์ ํ์ง ๋ชปํ๊ณ โฆ ์ ๊ฐ ๊ฐ๋ฐํ ๋ ์ฃผ๋ก ์ฌ์ฉํ๋ IOC ์ปจํ ์ด๋๋ Microsoft Extensions DependencyInjection ์ ๋๋ค
์ ๊ฐ ๊ตฌํํ๊ณ ์ํ๋ ๋๋ถ๋ถ์ IOC์ ๊ธฐ๋ฅ์ Microsoft Extensions DependencyInjection๊ณผ ๋ฎ์์์ต๋๋ค.
๊ตฌํํ๊ณ ์ ํ๋ ๊ธฐ๋ฅ
- Cache๊ฐ์ฒด์ NoneCache๊ฐ์ฒด ๋ฑ๋ก (Singleton, Transient)
- Interface์ ๊ฐ์ด ๊ฐ์ฒด๋ฅผ ๋ฑ๋ก
- ์์ฑ์ ์ฃผ์
- ๋ฏธ๋ฆฌ ์์ฑํ ๊ฐ์ฒด๋ฅผ ๋ฑ๋ก
- ๋๋ค๋ฅผ ์ด์ฉํ ๊ฐ์ฒด ์์ฑ ๋ฃจํด ๋ฑ๋ก
์ฐธ๊ณ ์๋ฃ
Carlos Blanco๋์ ํฌ์คํธ๋ฅผ ์ฐธ๊ณ ํ์ต๋๋ค.
๊ณ ๋ คํ์ง ์์ ์ฌํญ ๋ฐ ํ๊ณ
- ์ ๋์ ์ธ ์์น๋ฅผ ๊ฐ์ง๊ณ ๋ค๋ฅธ ์ ๋ช ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค๊ณผ ์ฑ๋ฅ๋ฑ์ ๋น๊ตํ์ง๋ ์์์ต๋๋คโฆ ๊ฐํโฆ์ ๊ฐโฆ
- ์ฒ์์๋ ์ธ๊ธ๋๋ ธ๋ค์ํผ ์ด๋ณด๊ธฐ ๋๋ฌธ์ ์ฝ๋๊ฐ ์ง์ ๋ถํฉ๋๋ค
- ๋ฒ๊ทธ๊ฐ ์์ ์ ์์ต๋๋ค.
๊ตฌํ ๊ณผ์
1. ์๋น์ค ๋ฑ๋ก์ ์ํ ์ธํฐํ์ด์ค
namespace ConvMVVM.Core.IOC
{
public interface IServiceCollection
{
public void RegisterCache<TInterface, TImplementation>() where TImplementation : TInterface;
//์ธํฐํ์ด์ค์ ๊ตฌ์์ฒด ํด๋์ค๋ฅผ ๊ฐ์ด ๋ฑ๋กํ๊ธฐ ์ํ ํจ์
public void RegisterNoneCache<TInterface, TImplementation>() where TImplementation : TInterface;
public void RegisterCache<TImplementation>() where TImplementation : class;
//๊ตฌ์์ฒด ํด๋์ค๋ง์ผ๋ก ๋ฑ๋กํ๊ธฐ ์ํ ํจ์
public void RegisterCache<TImplementation>(TImplementation implementation) where TImplementation : class;
//๋ฏธ๋ฆฌ ์์ฑํ ํด๋์ค๋ฅผ ๋ฑ๋กํ๊ธฐ ์ํ ํจ์
public void RegisterNoneCache<TImplementation>() where TImplementation : class;
public void RegisterCache<TInterface, TImplementation>(TImplementation implementation) where TImplementation : TInterface;
public void RegisterCache<TInterface, TImplementation>(Func<IContainer, TInterface> factory) where TImplementation : TInterface;
//๋๋ค๋ฅผ ์ด์ฉํ ์๋น์ค ์์ฑ ๋ฃจํด ๋ฑ๋ก์ ์ํ ํจ์
public void RegisterNoneCache<TInterface, TImplementation>(Func<IContainer, TInterface> factory) where TImplementation : TInterface;
public void RegisterCache<TImplementation>(Func<IContainer, TImplementation> factory) where TImplementation : class;
public void RegisterNoneCache<TImplementation>(Func<IContainer, TImplementation> factory) where TImplementation : class;
public bool CheckType(Type type);
//Container์์ ํ์
์กด์ฌ ์ ๋ฌด ํ๋ณ์ฉ ํจ์
public Tuple<Type, bool, object, object> GetType(Type type);
//ServiceCollection์ ํ์
์ ํค๋ก ๋ฑ๋ก๋ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์
public IContainer CreateContainer();
//์ปจํ
์ด๋ ์์ฑ์ ์ํ ํจ์
}
}
public void RegisterCache<TInterface, TImplementation>() where TImplementation : TInterface;
public void RegisterCache<TImplementation>() where TImplementation : class;
๊ฐ์ธ์ ์ผ๋ก ๋ง๋ค๋ฉด์ ํนํ๋ ํฅ๋ฏธ๋ก์ ๋ ๋ถ๋ถ์ ์ด ๋ถ๋ถ์ธ๋ฐ. generic TImplementation์ด TInterface์ ์์์ด ํ์ํ๋ค๋ ์ ํ์ ๊ฑธ์ ์๋ค๋ ๊ฒ์ด๋ค.
์โฆโฆ. ๊ทธ๋ฐ๋ฐ ๊ทธ์ ๋์์ TInterface๊ฐ interface๋ฉด์ TImplementation์ด class์ฌ์ผํจ์ ์ ํํ๋ ๊ฒ์ ์๋๋ ๊ฒ์ธ๊ฐ?โฆ
๊ณต๋ถ๋ฅผ ๋ํ ๊ฒ์ธ์ง ์๋ ์๋๋ ๊ฒ์ธ์งโฆ ์ฌ๋ฌ๊ฐ์ง ์๊ฐ์ด ๋ค์์ต๋๋ค.
2. ์๋น์ค ์ปจํ ์ด๋๋ฅผ ์ํ ์ธํฐํ์ด์ค
namespace ConvMVVM.Core.IOC
{
public interface IContainer
{
public TInterface GetService<TInterface>() where TInterface: class;
}
}
๋ถ์ด๊ตญ ๋ง๋ฅ ๋ด๋ฐฑํ๊ฒ ํ๋์ ํจ์๋ง ๋ฃ์์ต๋๋ค.
3. ServiceCollection ๊ตฌํ
namespace ConvMVVM.Core.IOC
{
public class ServiceCollection : IServiceCollection
{
#region Private Property
private readonly Dictionary<Type, Tuple<Type, bool, object, object>> Types = new Dictionary<Type, Tuple<Type, bool, object, object>>();
#endregion
#region Constructor
internal ServiceCollection()
{
}
#endregion
#region Static Functions
public static IServiceCollection Create()
{
return new ServiceCollection();
}
#endregion
#region Private Functions
private Tuple<Type, bool, object, object> CreateTypeInfo(Type type, bool cache, object cacheObject, object callback )
{
return new Tuple<Type, bool, object, object>(type, cache, cacheObject, callback);
}
#endregion
#region Public Functions
public void RegisterCache<TInterface, TImplementation>() where TImplementation : TInterface
{
this.Types[typeof(TInterface)] = this.CreateTypeInfo(typeof(TImplementation), true, null, null);
}
public void RegisterCache<TImplementation>() where TImplementation : class
{
this.Types[typeof(TImplementation)] = this.CreateTypeInfo(typeof(TImplementation), true, null, null);
}
public void RegisterCache<TImplementation>(TImplementation implementation) where TImplementation : class
{
this.Types[typeof(TImplementation)] = this.CreateTypeInfo(typeof(TImplementation), true, implementation, null);
}
public void RegisterNoneCache<TInterface, TImplementation>() where TImplementation : TInterface
{
this.Types[typeof(TInterface)] = this.CreateTypeInfo(typeof(TImplementation), false, null, null);
}
public void RegisterNoneCache<TImplementation>() where TImplementation : class
{
this.Types[typeof(TImplementation)] = this.CreateTypeInfo(typeof(TImplementation), false, null, null);
}
public void RegisterCache<TInterface, TImplementation>(TImplementation implementation) where TImplementation : TInterface
{
this.Types[typeof(TInterface)] = this.CreateTypeInfo(typeof(TImplementation), true, implementation, null);
}
public void RegisterCache<TInterface, TImplementation>(Func<IContainer, TInterface> factory) where TImplementation : TInterface
{
this.Types[typeof(TInterface)] = this.CreateTypeInfo(typeof(TImplementation), true, null, factory);
}
public void RegisterNoneCache<TInterface, TImplementation>(Func<IContainer, TInterface> factory) where TImplementation : TInterface
{
this.Types[typeof(TInterface)] = this.CreateTypeInfo(typeof(TImplementation), false, null, factory);
}
public void RegisterCache<TImplementation>(Func<IContainer, TImplementation> factory) where TImplementation : class
{
this.Types[typeof(TImplementation)] = this.CreateTypeInfo(typeof(TImplementation), true, null, factory);
}
public void RegisterNoneCache<TImplementation>(Func<IContainer, TImplementation> factory) where TImplementation : class
{
this.Types[typeof(TImplementation)] = this.CreateTypeInfo(typeof(TImplementation), false, null, factory);
}
public bool CheckType(Type type)
{
if (this.Types.ContainsKey(type)) return true;
else return false;
}
public IContainer CreateContainer()
{
return new Container(this);
}
public Tuple<Type, bool, object, object> GetType(Type type)
{
if (!CheckType(type))
{
throw new InvalidOperationException("Invalid key type");
}
return this.Types[type];
}
#endregion
}
}
#region Private Property
//ํ์
ํค, ํํ(๊ตฌ์์ฒด ํ์
, cache์ ๋ฌด, cache์ค๋ธ์ ํธ, ์์ฑ๋ฃจํด ์ฃผ์
์ ์ํ ๋๋ค ์ฝ๋ฐฑ)
private readonly Dictionary<Type, Tuple<Type, bool, object, object>> Types = new Dictionary<Type, Tuple<Type, bool, object, object>>();
#endregion
Dictionary๋ก ํ์ ํค๋ฅผ ํค๋ก ํํ๋ก ์์ฑ์ ํ์ํ ์ ๋ณด๋ฅผ ๋ฌถ์ด์ ๋ฃ์ ์ ์๋๋ก Types๋ผ๋ Dictionary๋ฅผ ๋ง๋ค์์ต๋๋ค.
#region Private Functions
//๊ฐ์ฒด ํ์
, cache ์ ๋ฌด, cache ์ค๋ธ์ ํธ, ์์ฑ๋ฃจํด lambda
private Tuple<Type, bool, object, object> CreateTypeInfo(Type type, bool cache, object cacheObject, object callback )
{
return new Tuple<Type, bool, object, object>(type, cache, cacheObject, callback);
}
#endregion
๊ฐ ์ธํฐํ์ด์ค ํจ์์ ๋ง๊ฒ ํ๋ธ ์ ๋ณด๋ฅผ ๋ง๋ค์ด์ Dictionary์ ๋ฑ๋ก์ ํ์ต๋๋ค.
์ด ์ ๋ณด๋ฅผ ์ด์ฉํด์ Container์์ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๊ฒ์ ๋๋ค.
//๋ด๊ฐ ๋ง๋ค ํ์
์ด ์๋์ง ํ์ธ
public bool CheckType(Type type)
{
if (this.Types.ContainsKey(type)) return true;
else return false;
}
public IContainer CreateContainer()
{
return new Container(this);
}
//ํ์
์ด ์๋ค๋ฉด ๊ทธ ํ์
์ ์์ฑ์ ์ํด ํ์ํ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๊ธฐ.
public Tuple<Type, bool, object, object> GetType(Type type)
{
if (!CheckType(type))
{
throw new InvalidOperationException("Invalid key type");
}
return this.Types[type];
}
๊ทธ ์ธ ๊ธฐํ ๊ฐ์ฒด ์์ฑ์ ์ํด ํ์ํ ํ์ ์กด์ฌ ์ ๋ฌด ์ฒดํฌ ํจ์์, ํ์ ์ ๋ฑ๋ก์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์๋ ๋ง๋ญ๋๋ค.
4. Container ๊ตฌํ
namespace ConvMVVM.Core.IOC
{
public class Container : IContainer
{
#region Private Property
private readonly IServiceCollection serviceCollection;
private readonly Dictionary<Type, object> cacheObjects = new Dictionary<Type, object>();
#endregion
#region Constructor
public Container(IServiceCollection services)
{
if(services == null)
{
throw new InvalidOperationException("Invalid service collection");
}
this.serviceCollection = services;
}
#endregion
#region Private Functions
public object Create(Type type)
{
if (!this.serviceCollection.CheckType(type))
{
throw new InvalidOperationException("There is no service key");
}
try
{
var typeInfo = this.serviceCollection.GetType(type);
var objectType = typeInfo.Item1;
var cacheOrNot = typeInfo.Item2;
var cacheObject = typeInfo.Item3;
var callback = typeInfo.Item4;
var defaultConstructors = objectType.GetConstructors();
if(defaultConstructors.Count() <= 0 && cacheObject == null)
{
throw new InvalidOperationException("There is no constructor");
}
if (cacheOrNot == false && callback == null && cacheObject == null)
{
var defaultConstructor = defaultConstructors[0];
var defaultParams = defaultConstructor.GetParameters();
var parameters = defaultParams.Select(param => Create(param.ParameterType)).ToArray();
var service = defaultConstructor.Invoke(parameters);
return service;
}
if(cacheOrNot == false && callback != null && cacheObject == null)
{
var methodInfo = callback.GetType().GetMethod("Invoke");
var service = methodInfo.Invoke(callback, new[] { this });
return service;
}
if(cacheOrNot == true && callback == null && cacheObject == null)
{
if (this.cacheObjects.ContainsKey(type) == true)
return this.cacheObjects[type];
var defaultConstructor = defaultConstructors[0];
var defaultParams = defaultConstructor.GetParameters();
var parameters = defaultParams.Select(param => Create(param.ParameterType)).ToArray();
var service = defaultConstructor.Invoke(parameters);
this.cacheObjects[type] = service;
return service;
}
if(cacheOrNot == true && callback != null && cacheObject == null)
{
if (this.cacheObjects.ContainsKey(type) == true)
return this.cacheObjects[type];
var methodInfo = callback.GetType().GetMethod("Invoke");
var service = methodInfo.Invoke(callback, new[] { this });
this.cacheObjects[type] = service;
return service;
}
if (cacheOrNot == true && callback == null && cacheObject != null)
{
if (this.cacheObjects.ContainsKey(type) == true)
return this.cacheObjects[type];
this.cacheObjects[type] = cacheObject;
return cacheObject;
}
throw new InvalidOperationException("Invalid service collection infomation");
}
catch (Exception ex)
{
throw new InvalidOperationException("Unknown", ex);
}
}
#endregion
#region Functions
public TInterface GetService<TInterface>() where TInterface : class
{
try
{
return (TInterface)Create(typeof(TInterface));
}catch(Exception ex)
{
throw new InvalidOperationException("Unknown", ex);
}
}
#endregion
}
}
๊ฐ์ฅ ์ค์ํ ๋ถ๋ถ์ public object Create(Type type) ์ด ํจ์์ธ๋ฐ ๊ฐ ๊ฐ์ฒด ์์ฑ์ ํ์ํ ์ ๋ณด์ ๋ง์ถฐ ๊ฐ์ฒด๋ฅผ ์์ฑํฉ๋๋ค.
์ด 5๊ฐ์ง์ ๋์ ๊ฒฝ์ฐ๊ฐ ๋ฐ์ํ๋๋ฐ
- cache==false, cache์ค๋ธ์ ํธ๊ฐ ์์ผ๋ฉฐ ์์ฑ๋ฃจํด callback์ด ์๋ค๋ฉด โ reflection์ ์ด์ฉํ์ฌ NoneCache๋ก ๊ฐ์ฒด ์์ฑ
- cache==false, cache์ค๋ธ์ ํธ๊ฐ ์์ผ๋ฉฐ ์์ฑ๋ฃจํด callback์ด ์๋ค๋ฉด โ reflection์ ์ด์ฉํ์ฌ NoneCache๋ฅผ callback์ผ๋ก ์์ฑ
- cache==true, cache์ค๋ธ์ ํธ๊ฐ ์์ผ๋ฉฐ ์์ฑ๋ฃจํด callback์ด ์๋ค๋ฉด โ reflection์ ์ด์ฉํ์ฌ Cache๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ Cache๊ฐ์ฒด ํ ์ด๋ธ์ ๋ฑ๋กํ์ฌ ์๋ช ๊ด๋ฆฌ
- cache==true, cache์ค๋ธ์ ํธ๊ฐ ์์ผ๋ฉฐ ์์ฑ๋ฃจํด callback์ด ์๋ค๋ฉด โ cache์ค๋ธ์ ํธ๋ฅผ ๊ทธ๋๋ก Cache๊ฐ์ฒด ํ ์ด๋ธ์ ๋ฑ๋กํ์ฌ ์๋ช ๊ด๋ฆฌ
- cache==true, cache์ค๋ธ์ ํธ๊ฐ ์์ผ๋ฉฐ ์์ฑ๋ฃจํด callback์ด ์๋ค๋ฉด โ reflection์ ์ด์ฉํ์ฌ Cache๊ฐ์ฒด๋ฅผ callback์ผ๋ก ์์ฑ, Cache๊ฐ์ฒด ํ ์ด๋ธ์ ๋ฑ๋กํ์ฌ ์๋ช ๊ด๋ฆฌ
์์ ๊ฐ์ ๋ก์ง์ผ๋ก ์์ฑ๋๋ฉฐโฆ ์์ฑ์ ์ฃผ์ ์ ์ํด์ Reflection๊ณผ Createํจ์๋ฅผ ์ฌ๊ท์ ์ผ๋ก Linq์ Select์ ๊ฐ์ด ์์ด์ >ํธ์ถํฉ๋๋ค.
๊ทธ๋ฌ๋ฉด ๊ฐ ์์ฑ์์ ํ์ํ ๊ฐ์ฒด๋ฅผ ์์ฑ์ ์ฃผ์ ํ ์ํ๋ก ์์ฑํ๊ฒ ๋ฉ๋๋ค.
IOC์ปจํ ์ด๋ ์ฌ์ฉ
๋ง๋ค์ด๋ดค์ผ๋ ์ด์ ๋ ์จ๋ด์ผ ํฉ๋๋คโฆ
IOC์ปจํ ์ด๋๋ฅผ ์ฐ๋ ์ฌ๋ฌ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์๊ฒ ์ง๋งโฆ ์ ๊ฐ ๊ฐ์ธ์ ์ผ๋ก ๊ฐ๋ฐํ๋ฉด์ ๋๊ผ๋ ์ฐ์์๋ฅผ ์ ๋ฆฌํ์ฌ ์๋์ ๊ฐ์ ์ผ์ด์ค๋ก ๋๋ ๋ดค์ต๋๋ค.
์ฌ๋ก #1
์ธํฐํ์ด์ค๊ฐ ์์๋, ์๋น์ค๋ฅผ ์์ฑ์ ์ฃผ์ ๊ฐ์ฒด์ฌ๋ก #2
A Model์ ํ๊ณ ์๋ A ViewModel ์์ฑ ํ์ง๋ง A Model์ Ioc๋ฑ๋ก์ ํ๊ณ ์ถ์ง ์์๋์ฌ๋ก #3
A Model์ ํ๊ณ ์๋ A ViewModel ๋ฌถ์์ ์์ฑ ํ์ง๋ง A Model์ Ioc๋ฑ๋ก์ ํ๊ณ ์ถ์ง ์์๋์ฌ๋ก #4
A, B, C Model์ Property ์ฃผ์ ์ ๋ฐ์์ D ViewModel ์์ฑ. ํ์ง๋ง A, B, C๋ชจ๋ธ์ IoC๋ฑ๋ก์ ํ๊ณ ์ถ์ง ์์๋
์ฌ๋ก #1
์ธํฐํ์ด์ค๊ฐ ์์๋, ์๋น์ค๋ฅผ ์์ฑ์ ์ฃผ์ ํ ๊ฐ์ฒด
//TestModel
namespace IOCContainerExample.Model
{
public class TestModel : ITestModel
{
#region Private Property
private readonly TestService testService;
#endregion
#region Constructor
public TestModel(TestService _testService) {
this.testService = _testService;
}
#endregion
#region Functions
public string Test()
{
return this.testService.Test();
}
#endregion
}
}
TestModel ํด๋์ค ๊ตฌํ๋ถ
namespace IOCContainerExample.Service
{
public class TestService
{
#region Consturctor
public TestService() { }
#endregion
#region Public Property
public string Test()
{
return "there is no cow level";
}
#endregion
}
}
TestService ํด๋์ค ๊ตฌํ๋ถ
var collection = ServiceCollection.Create();
collection.RegisterCache<TestService>();
collection.RegisterCache<ITestModel, TestModel>();
var container = collection.CreateContainer();
var tesetModel = container.GetService<ITestModel>();
System.Console.WriteLine(tesetModel.Test());
IoC์ปจํ ์ด๋ ๋ฑ๋ก ๋ฐ ๊ฐ์ฒด ์์ฑ ์ฌ์ฉโฆ ์ด์ ๋๋ IoC ์ฐ์๋ ๋ถ์ด๋ผ๋ฉด ์ ์๊ณ ๊ณ์ค๊ฒ๋๋ค.
์ฌ๋ก #2
A Model์ ํ๊ณ ์๋ A ViewModel ์์ฑ ํ์ง๋ง A Model์ IoC๋ฑ๋ก์ ํ๊ณ ์ถ์ง ์์๋.
namespace IOCContainerExample.Model
{
public class AModel
{
#region Constructor
public AModel() { }
#endregion
}
}
AModel ํด๋์ค ๊ตฌํ๋ถ
namespace IOCContainerExample.ViewModel
{
public class AViewModel
{
#region Constructor
public AViewModel()
{
}
#endregion
#region Public Property
public AViewModel AModel { get; set; }
#endregion
}
}
AViewModel ํด๋์ค ๊ตฌํ๋ถ
var collection = ServiceCollection.Create();
collection.RegisterCache<AViewModel>();
collection.RegisterNoneCache<Func<AModel, AViewModel>>((container)=>
{
return (model) =>
{
var vm = container.GetService<AViewModel>();
vm.AModel = model;
return vm;
};
});
var container = collection.CreateContainer();
var converter = container.GetService<Func<AModel, AViewModel>>();
var model = new AModel();
var viewModel = converter(model);
System.Console.WriteLine("test");
์ด ๊ฒฝ์ฐ๋ฅผ ์ํด์ Microsoft Extensions DependencyInjection ์์ ๋๋ค ์์ฑ์ ์ง์ํ๋ ๋ด ๋๋คโฆ
์ฌ๋ก #3
A Model์ ํ๊ณ ์๋ A ViewModel ๋ฌถ์์ ์์ฑ ํ์ง๋ง A Model์ Ioc๋ฑ๋ก์ ํ๊ณ ์ถ์ง ์์๋
var collection = ServiceCollection.Create();
collection.RegisterCache<AViewModel>();
collection.RegisterNoneCache<Func<AModel, AViewModel>>((container) =>
{
return (model) =>
{
var vm = container.GetService<AViewModel>();
vm.AModel = model;
return vm;
};
});
collection.RegisterNoneCache<Func<List<AModel>, List<AViewModel>>>((container) =>
{
return (models) =>
{
var converter = container.GetService<Func<AModel, AViewModel>>();
var vms = models.Select(model => converter(model)).ToList();
return vms;
};
});
var container = collection.CreateContainer();
var converter = container.GetService<Func<List<AModel>, List<AViewModel>>>();
var models = new List<AModel>()
{
new AModel(),
new AModel(),
new AModel()
};
var viewModels = converter(models);
์ฌ๋ก #4
A, B, C Model์ Property ์ฃผ์ ์ ๋ฐ์์ D ViewModel ์์ฑ. ํ์ง๋ง A, B, C๋ชจ๋ธ์ IoC๋ฑ๋ก์ ํ๊ณ ์ถ์ง ์์๋
var collection = ServiceCollection.Create();
collection.RegisterCache<DViewModel>();
collection.RegisterNoneCache<Func<AModel, BModel, CModel, DViewModel>>((container) =>
{
return (amodel, bmodel, cmodel) =>
{
var vm = container.GetService<DViewModel>();
vm.AModel = amodel;
vm.BModel = bmodel;
vm.CModel = cmodel;
return vm;
};
});
var container = collection.CreateContainer();
var amodel = new AModel();
var bmodel = new BModel();
var cmodel = new CModel();
var converter = container.GetService<Func<AModel, BModel, CModel, DViewModel>>();
var viewModel = converter(amodel, bmodel, cmodel);
๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ Property Injection์ ์ง์ํ์ง์๋๋ผ๋ ๋๋ค ์ฃผ์ ์ ํตํด์ ์ด๋์ ๋ ๊ทน๋ณต์ด ๊ฐ๋ฅํฉ๋๋ค.
์์ผ๋ก ์ถ๊ฐ ํน์ ๊ฐ์ ๋์ด์ผ ๋ ์ฌํญ
์ ์์ ์์๋ ๋ณด๋ค์ํผ Property Injection์ ์ง์ํ๋ Attribute๊ฐ ์์ผ๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ ํ์ต๋๋ค.
๋ค๋ฅธ IoC ์ปจํ ์ด๋์์๋ ์ง์์ ํ๋๊ฒ ๊ฐ๋๋ฐโฆ
Microsoft Extensions DependencyInjection ์์ ์ง์์ ์ํ๋ ์ด์ ๋ ๋ชจ๋ฅด๊ฒ ์ผ๋ ์๋ง๋ ๋๋ค๋ฅผ ์ด์ฉํด์ ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ด ์๋๊ฐ์?