Позвольте мне представить свой подход под названием Yappi . Он относится к генераторам производного класса Runtime proxy, добавляя новые функции к существующему объекту или типу, например Dynamic Proxy от Caste Project.
Он позволяет реализовать INotifyPropertyChanged один раз в базовом классе, а затем объявлять производные классы в следующих стиль, поддерживающий INotifyPropertyChanged для новых свойств:
public class Animal:Concept
{
protected Animal(){}
public virtual string Name { get; set; }
public virtual int Age { get; set; }
}
Сложность построения производного класса или прокси может быть скрыта за следующей строкой:
var animal = Concept.Create.New();
И вся работа по реализации INotifyPropertyChanged может сделайте это следующим образом:
public class Concept:INotifyPropertyChanged
{
//Hide constructor
protected Concept(){}
public static class Create where TConcept:Concept
{
//Construct derived Type calling PropertyProxy.ConstructType
public static readonly Type Type = PropertyProxy.ConstructType>(new Type[0], true);
//Create constructing delegate calling Constructor.Compile
public static Func New = Constructor.Compile>(Type);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(PropertyChangedEventArgs eventArgs)
{
var caller = PropertyChanged;
if(caller!=null)
{
caller(this, eventArgs);
}
}
//define implementation
public class Implementation : DefaultImplementation where TConcept:Concept
{
public override Func OverrideGetter(PropertyInfo property)
{
return PropertyImplementation.GetGetter(property.Name);
}
///
/// Overriding property setter implementation.
///
/// Base type for implementation. TBaseType must be TConcept, and inherits all its constraints. Also TBaseType is TDeclaringType.
/// Type, declaring property.
/// Constructed type. TConstructedType is TDeclaringType and TBaseType.
/// Type of property.
/// PropertyInfo of property.
/// Delegate, corresponding to property setter implementation.
public override Action OverrideSetter(PropertyInfo property)
{
//This code called once for each declared property on derived type's initialization.
//EventArgs instance is shared between all events for each concrete property.
var eventArgs = new PropertyChangedEventArgs(property.Name);
//get delegates for base calls.
Action setter = PropertyImplementation.GetSetter(property.Name);
Func getter = PropertyImplementation.GetGetter(property.Name);
var comparer = EqualityComparer.Default;
return (pthis, value) =>
{//This code executes each time property setter is called.
if (comparer.Equals(value, getter(pthis))) return;
//base. call
setter(pthis, value);
//Directly accessing Concept's protected method.
pthis.OnPropertyChanged(eventArgs);
};
}
}
}
Он полностью безопасен для рефакторинга, не использует отражения после построения типа и достаточно быстро.
В SQL Server 2017 вы можете использовать OPENJSON
для получения строки JSON как есть:
SELECT *
FROM skills
WHERE EXISTS (
SELECT 1
FROM OPENJSON('["Sports", "Life", "Relationship"]', ' Демонстрация на db <> fiddle [ 115]) AS j
WHERE skills.description LIKE '%' + j.value + '%'
)
Демонстрация на db <> fiddle [ 115]
Простой вызов map()
в массиве words
позволит вам сгенерировать соответствующие запросы, которые вы затем сможете выполнить (с объединением или без объединения их сначала в одну строку).
Демо:
var words = ["Sports", "Life", "Relationship"];
var template = "Select * From Skills Where Description Like ('%{0}%')";
var queries = words.map(word => template.replace('{0}', word));
var combinedQuery = queries.join("\r\n");
console.log(queries);
console.log(combinedQuery);