Предупреждение. Возможно, это не очень хороший шаблон проектирования.
На практике цепочка зависимостей должна быть View
=> ViewModel
=> Model
(=>
означает «зависит от»). Model
не должен ничего знать о ViewModel
(то есть через атрибуты, в коде ниже).
Ответ, приведенный ниже, является всего лишь приспособлением для того, что вы просили в вопросе.
Я не думаю, что есть действительно "чистые" способы, которыми вы можете сделать это без использования рефлексии. Тем не менее, мы можем сделать оставшуюся часть кода чистой, используя отражение (цена которого заключается в использовании отражения :)).
Теперь я предлагаю решение с использованием атрибутов.
Помните: этот метод работает, только если у вас есть открытый конструктор для каждого ViewModel
класса, который принимает один Product
объект в качестве параметра! Если нет, решение Варуна было бы лучше (вам нужен функция отображения в любом случае в этом случае).
using System;
using System.Diagnostics;
using System.Linq;
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
sealed class UseViewModelAttribute : Attribute
{
public Type ViewModelType { get; }
public UseViewModelAttribute(Type viewModelType)
{
Debug.Assert(typeof(IViewModel).IsAssignableFrom(viewModelType));
ViewModelType = viewModelType;
}
}
class ViewModelFactory
{
private readonly static Type[] ctorParams = new Type[] { typeof(IProduct) };
public IViewModel CreateViewModel(IProduct product)
{
var vmType = (product.GetType().GetCustomAttributes(false).FirstOrDefault(attr
=> attr is UseViewModelAttribute) as UseViewModelAttribute)?.ViewModelType;
Debug.Assert(!(vmType is null));
return Activator.CreateInstance(vmType, product) as IViewModel;
}
}
Чтобы использовать это, добавьте UseViewModel(typeof(ViewModelForThisProductType))
перед вашими Product
классами. Как:
[UseViewModel(typeof(ProductAViewModel))]
class ProductA : IProduct { }
[UseViewModel(typeof(ProductBViewModel))]
class ProductB : IProduct { }
Ваши ViewModel
классы должны выглядеть следующим образом:
class ProductAViewModel : IViewModel {
//You can use both IProduct or the derived type (i.e ProductA) as the constructor param
public ProductAViewModel(ProductA a)
{
}
}
class ProductBViewModel : IViewModel {
public ProductBViewModel(IProduct b)
{
}
}