public async void OnJavaScriptObjectChanges(IJavascriptObject objectchanged, string propertyName, IJavascriptObject newValue) { try { var res = _SessionCache.GetCached(objectchanged) as JsGenericObject; if (res == null) { return; } var propertyAccessor = new PropertyAccessor(res.CValue, propertyName, _Logger); if (!propertyAccessor.IsSettable) { _Logger.Info(() => $"Unable to set C# from javascript object: property: {propertyName} is readonly."); return; } var targetType = propertyAccessor.GetTargetType(); var glue = GetCachedOrCreateBasic(newValue, targetType); var bridgeUpdater = glue.IsBasicNotNull() ? null : new BridgeUpdater(); await Context.RunOnUIContextAsync(() => { using (var relisten = glue.IsBasicNotNull() ? null : ReListen(bridgeUpdater)) using (_IsListening ? _ListenerRegister.GetPropertySilenter(res.CValue) : null) { var oldValue = propertyAccessor.Get(); propertyAccessor.Set(glue.CValue); var actualValue = propertyAccessor.Get(); if (Object.Equals(actualValue, glue.CValue)) { res.UpdateGlueProperty(propertyName, glue); return; } if (!Object.Equals(oldValue, actualValue)) { CSharpPropertyChanged(res.CValue, new PropertyChangedEventArgs(propertyName)); } } }); if (!(bridgeUpdater?.HasUpdatesOnJavascriptContext == true)) { return; } await Context.RunOnJavascriptContextAsync(() => { bridgeUpdater.UpdateOnJavascriptContext(Context.ViewModelUpdater); }); } catch (Exception e) { _Logger.Error(() => $"Unable to update ViewModel from View, exception raised: {e.Message}"); } }
private async void CSharpPropertyChanged(object sender, PropertyChangedEventArgs e) { var pn = e.PropertyName; var propertyAccessor = new PropertyAccessor(sender, pn, _Logger); if (!propertyAccessor.IsGettable) { return; } var currentfather = _SessionCache.GetCached(sender) as JsGenericObject; if (currentfather == null) { return; } var nv = propertyAccessor.Get(); var oldbridgedchild = currentfather.Attributes[pn]; if (Object.Equals(nv, oldbridgedchild.CValue)) { return; } await RegisterAndDo(() => _JSObjectBuilder.UnsafelMap(nv), (child) => currentfather.ReRoot(pn, child)); }
private static Func <object[], object[], object> CreateInstanceFactory(Projection projection) { if (projection.ctor == null) { return((_, a) => a[0]); } var compiledCtorDelegate = ReflectionHelpers.GetCompiledDelegate(projection.ctor); if (projection.initMembers == null) { return((ctorArguments, _) => compiledCtorDelegate(null, ctorArguments)); } var memberAccessors = new PropertyAccessor[projection.initMembers.Length]; for (var i = 0; i < memberAccessors.Length; i++) { var property = (PropertyInfo)projection.initMembers[i]; memberAccessors[i] = PropertyAccessor.Get(property); } return(delegate(object[] ctorArguments, object[] arguments) { var result = compiledCtorDelegate(null, ctorArguments); for (var i = 0; i < memberAccessors.Length; i++) { memberAccessors[i].Set(result, arguments[i]); } return result; }); }
/// <summary> /// Converts to asynchronous proxy (if possible) /// </summary> /// <param name="service">The synchronous proxy</param> public static AsyncOrganizationServiceProxy ToAsyncService(this OrganizationServiceProxy service) { if (!OrganizationServiceConfigurationType.IsAssignableFrom(service.ServiceConfiguration.GetType())) { throw new InvalidOperationException($"Cannot create {nameof(AsyncOrganizationServiceProxy)} from {nameof(OrganizationServiceProxy)}, because a customer service configuration is used. Expected service configuration type is '{OrganizationServiceConfigurationType}', but got '{service.ServiceConfiguration.GetType()}'"); } var primaryEndpoint = _primaryEndpoint.Get(service.ServiceConfiguration); var asyncService = new AsyncOrganizationServiceProxy(primaryEndpoint, service.HomeRealmUri, service.ClientCredentials, service.DeviceCredentials); asyncService.Timeout = service.Timeout; asyncService.UserPrincipalName = service.UserPrincipalName; asyncService.EndpointAutoSwitchEnabled = service.EndpointAutoSwitchEnabled; asyncService.CallerId = service.CallerId; asyncService.SyncOperationType = service.SyncOperationType; asyncService.SdkClientVersion = service.SdkClientVersion; #if SDK8AtLeast asyncService.UserType = service.UserType; asyncService.CallerRegardingObjectId = service.CallerRegardingObjectId; #endif foreach (var behavior in service.ServiceConfiguration.CurrentServiceEndpoint.Behaviors) { asyncService.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(behavior); } return(asyncService); }
public void TestPropertyDoesntExistOnInterfaceTarget() { var propC = PropertyAccessor.Get <Client>(x => x.ModifiedByUserId); var propICC = propC.Get <ICreateFields>(); Assert.IsNull(propICC); }
/// <summary> /// Gets a Dictionary of Plus, Netural, and Minus keys containing a list of the racial modifiers. /// </summary> /// <returns>A Dictionary object with Plus, Netural, and Minus keys.</returns> public virtual Dictionary <string, List <string> > GetRacialModifiers() { List <string> plusModifiers = new List <string>(); List <string> neturalModifiers = new List <string>(); List <string> minusModifiers = new List <string>(); foreach (string racialModifier in Race.RacialModifiers) { // Access the racial properties by string name PropertyAccessor prop = new PropertyAccessor(typeof(Race), racialModifier); int value = (int)prop.Get(this); // Which category is the value? if (value > 0) { plusModifiers.Add(racialModifier); } else if (value < 0) { minusModifiers.Add(racialModifier); } else { neturalModifiers.Add(racialModifier); } } return(new Dictionary <string, List <string> > { { "Plus", plusModifiers }, { "Netural", neturalModifiers }, { "Minus", minusModifiers } }); }
private void CSharpPropertyChanged(object sender, PropertyChangedEventArgs e) { var pn = e.PropertyName; var propertyAccessor = new PropertyAccessor(sender, pn, _Logger); if (!propertyAccessor.IsGettable) { return; } var currentfather = _SessionCache.GetCached(sender) as JsGenericObject; if (currentfather == null) { return; } var nv = propertyAccessor.Get(); var oldbridgedchild = currentfather.Attributes[pn]; if (Object.Equals(nv, oldbridgedchild.CValue)) { return; } UpdateFromCSharpChanges(nv, (child) => currentfather.GetUpdater(pn, child)).DoNotWait(); }
public void TestSourceAndTargetCannotBothBeClasses() { var propU = PropertyAccessor.Get <User>(x => x.Id); var propE = PropertyAccessor.Get <Employee>(x => x.Id); Assert.Throws <InvalidOperationException>(() => propU.Get <Employee>()); Assert.Throws <InvalidOperationException>(() => propE.Get <User>()); }
public void TestSourceAndTargetCannotBothBeInterfaces() { var propIC = PropertyAccessor.Get <ICreateFields>(x => x.CreatedByUserId); var propICE = PropertyAccessor.Get <ICreateEditFields>(x => x.CreatedByUserId); Assert.Throws <InvalidOperationException>(() => propIC.Get <ICreateEditFields>()); Assert.Throws <InvalidOperationException>(() => propICE.Get <ICreateFields>()); }
object[] IMetaDataProvider.GetPrimaryKeyValue <T>(T entity) { var primaryKey = ((IMetaDataProvider)this).GetPrimaryKey <T>(); var values = new object[primaryKey.Length]; for (var i = 0; i < primaryKey.Length; i++) { values[i] = PropertyAccessor.Get(entity, primaryKey[i]); } return(values); }
public void TestFindsOriginalInterface() { //--Arrange var propC = PropertyAccessor.Get <Client>(x => x.CreatedByUserId); //--Act var(type, property) = propC.GetDeclaringType(true); //--Assert Assert.AreEqual(typeof(ICreateFields), type); Assert.AreEqual(typeof(ICreateFields), property.DeclaringType); }
internal object[] GetPrimaryKeyValue(object entity, DbContext context) { var entityType = entity.GetType(); var primaryKey = _keys.GetOrAdd(entityType, t => GetPrimaryKeyFromTypeHierarchy(t, context)); var values = new object[primaryKey.Length]; for (var i = 0; i < primaryKey.Length; i++) { values[i] = PropertyAccessor.Get(entityType, entity, primaryKey[i]); } return(values); }
public object[] GetPrimaryKeyValue <T>(T entity, DbContext context) where T : class { var primaryKey = GetPrimaryKey <T>(context); var values = new object[primaryKey.Length]; for (var i = 0; i < primaryKey.Length; i++) { values[i] = PropertyAccessor.Get(entity, primaryKey[i]); } return(values); }
private static void CascadeImplementation <T>(T root, Action <T, T> action, HashSet <T> ancestors, IReadOnlyCollection <string> paths = null, int level = 0) { ancestors = ancestors ?? new HashSet <T>(); ancestors.Add(root); var set = new HashSet <string>(paths != null ? paths.Select(i => i.Split('.')).Select(i => i.ElementAtOrDefault(level)).Where(i => i != null) : Enumerable.Empty <string>()); var properties = root.GetType().GetProperties(); if (paths != null) { properties = properties.Where(p => set.Contains(p.Name)).ToArray(); } var objectProperties = properties.Where(t => typeof(T).IsAssignableFrom(t.PropertyType)); var collectionProperties = properties.Where(t => t.PropertyType.IsGenericType && (t.PropertyType.IsClass || typeof(IEnumerable).IsAssignableFrom(t.PropertyType)) && typeof(ICollection <T>).IsAssignableFrom(t.PropertyType.GetGenericTypeDefinition().MakeGenericType(typeof(T))) && typeof(T).IsAssignableFrom(t.PropertyType.GetGenericArguments()[0])); foreach (var property in objectProperties) { var item = PropertyAccessor.Get(root.GetType(), root, property.Name); if (!(item is T) || ancestors.Contains((T)item)) { continue; } action(root, (T)item); CascadeImplementation((T)item, action, ancestors, paths, level + 1); } foreach (var property in collectionProperties) { var items = (IEnumerable)PropertyAccessor.Get(root.GetType(), root, property.Name); if (items == null) { continue; } foreach (var item in items) { if (!(item is T) || ancestors.Contains((T)item)) { continue; } action(root, (T)item); CascadeImplementation((T)item, action, ancestors, paths, level + 1); } } }
private static void MergeObjectProperties(DbContext context, object source, object target, IEqualityComparer <object> comparer, HashSet <object> ancestors, IReadOnlyCollection <string[]> paths, int level, PropertyInfo[] properties) { foreach (var property in properties.Where(p => p.PropertyType != typeof(string) && p.CanRead && p.CanWrite && p.PropertyType.IsClass && !typeof(IEnumerable).IsAssignableFrom(p.PropertyType))) { var value = PropertyAccessor.Get(target.GetType(), target, property.Name); var newValue = PropertyAccessor.Get(source.GetType(), source, property.Name); if (ancestors.Contains(newValue)) { continue; } if (value == null && newValue != null) { context.Entry(target).Member(property.Name).CurrentValue = newValue; } else if (newValue == null && value != null) { context.Entry(target).Member(property.Name).CurrentValue = null; } else if (value != null) { try { context.Entry(value).CurrentValues.SetValues(newValue); } catch (Exception ex) { // Merge failed as we tried to change the parent // Now try actually changing the parent var hash = comparer.GetHashCode(newValue); var local = GetLocal(context, newValue.GetType()); var attached = local.Cast <object>().FirstOrDefault(e => comparer.GetHashCode(e) == hash); if (attached != null && attached != newValue) { // Found unchanged locally // Assign existing parent PropertyAccessor.Set(target.GetType(), target, property.Name, attached); } else { PropertyAccessor.Set(target.GetType(), target, property.Name, newValue); context.Entry(newValue).State = EntityState.Unchanged; } } MergeImplementation(context, newValue, value, comparer, new HashSet <object>(ancestors), paths, level + 1); } } }
public IEnumerable <IPropertyChange> GetChangedProperties() { var simpleProperties = _originalValues.Select(x => new SimplePropertyChange( x.Key, x.Value, PropertyAccessor.Get(Target.GetType().GetProperty(x.Key)).GetValue(Target))) .Cast <IPropertyChange>(); var collectionProperties = _collectionProxies .Where(x => x.Value.Added.Any() || x.Value.Removed.Any()) .Select(x => new CollectionPropertyChange(x.Key, x.Value.Added, x.Value.Removed)) .Cast <IPropertyChange>(); return(simpleProperties.Concat(collectionProperties).ToList()); }
public void TestInheritedImplementation() { var propI = PropertyAccessor.Get <IGuidIdentifier>(x => x.Id); var propU = PropertyAccessor.Get <User>(x => x.Id); var propE = PropertyAccessor.Get <Employee>(x => x.Id); var propEI = propI.Get <Employee>(); Console.WriteLine($"I: {propI.ReflectedType}.{propI.Name}"); Console.WriteLine($"U: {propU.ReflectedType}.{propU.Name}"); Console.WriteLine($"E: {propE.ReflectedType}.{propE.Name}"); Console.WriteLine($"EI: {propEI?.ReflectedType}.{propEI?.Name}"); //--Employee inherits User, so the property is actually User's Assert.AreEqual(propU, propE); Assert.AreEqual(typeof(User), propEI?.DeclaringType); Assert.AreEqual(typeof(Employee), propEI?.ReflectedType); }
public static string GenerateHelp(Type self) { var properties = PropertyAccessor.Get(self, true); StringBuilder sb = new StringBuilder(properties.Count() * 800); sb.AppendLine(""); foreach (var property in properties) { if (!property.CanWrite) { continue; } sb.AppendLine(property.Name); sb.AppendLine($"\ttype : {property.Type.Name}"); if (property.Required) { sb.AppendLine("\tRequired"); } if (!string.IsNullOrEmpty(property.DisplayDescription)) { sb.AppendLine($"\tdescription : {property.DisplayDescription}"); } //if (property.DefaultValue != null) // sb.AppendLine($"\tdefault value : {property.DefaultValue}"); if (property.Type.IsEnum) { sb.Append("\tRestricted values ("); foreach (var item in Enum.GetNames(property.Type)) { sb.Append($"{item}, "); } sb.Remove(sb.Length - 2, 2); sb.AppendLine(")"); } } return(sb.ToString()); }
/// <summary> /// Creates the async version of the service /// </summary> /// <param name="service">Synchronous service proxy</param> public static AsyncDiscoveryServiceProxy ToAsyncService(this DiscoveryServiceProxy service) { if (!DiscoveryServiceConfigurationType.IsAssignableFrom(service.ServiceConfiguration.GetType())) { throw new InvalidOperationException($"Cannot create {nameof(AsyncDiscoveryServiceProxy)} from {nameof(DiscoveryServiceProxy)}, because a customer service configuration is used. Expected service configuration type is '{DiscoveryServiceConfigurationType}', but got '{service.ServiceConfiguration.GetType()}'"); } var primaryEndpoint = _primaryEndpoint.Get(service.ServiceConfiguration); var asyncService = new AsyncDiscoveryServiceProxy(primaryEndpoint, service.HomeRealmUri, service.ClientCredentials, service.DeviceCredentials); asyncService.Timeout = service.Timeout; asyncService.UserPrincipalName = service.UserPrincipalName; asyncService.EndpointAutoSwitchEnabled = service.EndpointAutoSwitchEnabled; foreach (var behavior in service.ServiceConfiguration.CurrentServiceEndpoint.Behaviors) { asyncService.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(behavior); } return(asyncService); }
public void Get_Performance_Test_Stress() { var @object = new FakeClass(); var stopWatch = new Stopwatch(); stopWatch.Start(); var operations = 100000000; var propertyInfo = typeof(FakeClass).GetProperty("Available2", BindingFlags.Public | BindingFlags.Instance); var description = new PropertyInfoDescription(propertyInfo); var myTypeInstrospector = new PropertyAccessor(typeof(FakeClass), description, 0); for (var i = 0; i < operations; i++) { var res = myTypeInstrospector.Get(@object); } stopWatch.Stop(); var ts = stopWatch.ElapsedMilliseconds; _Output.WriteLine($"Perf: {operations* 1000/ts} operations per sec"); }
public void TestGettingInterfaceFromClass() { var propIC = PropertyAccessor.Get <ICreateFields>(x => x.CreatedByUserId); var propICE = PropertyAccessor.Get <ICreateEditFields>(x => x.CreatedByUserId); var propC = PropertyAccessor.Get <Client>(x => x.CreatedByUserId); var propICC = propC.Get <ICreateFields>(); var propICEC = propC.Get <ICreateEditFields>(); Console.WriteLine($"IC: {propIC.ReflectedType}.{propIC.Name}"); Console.WriteLine($"ICE: {propICE.ReflectedType}.{propICE.Name}"); Console.WriteLine($"C: {propC.ReflectedType}.{propC.Name}"); Console.WriteLine($"ICC: {propICC?.ReflectedType}.{propICC?.Name}"); Console.WriteLine($"ICEC: {propICEC?.ReflectedType}.{propICEC?.Name}"); Assert.AreEqual(propIC, propICE); Assert.IsNull(propICEC); //--The implementing class is not the same as the interface... Assert.AreNotEqual(propC, propIC); Assert.AreNotEqual(propC, propICE); //--...though the class can be mapped to the interface in question Assert.AreEqual(propIC, propICC); }
private static void CascadeImplementation <T>(T root, Action <T, T> action, HashSet <T> ancestors) { ancestors = ancestors ?? new HashSet <T>(); ancestors.Add(root); var properties = root.GetType().GetProperties(); var objectProperties = properties.Where(t => typeof(T).IsAssignableFrom(t.PropertyType)); var collectionProperties = properties.Where(t => t.PropertyType.IsGenericType && (t.PropertyType.IsClass || typeof(IEnumerable).IsAssignableFrom(t.PropertyType)) && typeof(ICollection <T>).IsAssignableFrom(t.PropertyType.GetGenericTypeDefinition().MakeGenericType(typeof(T))) && typeof(T).IsAssignableFrom(t.PropertyType.GetGenericArguments()[0])); foreach (var property in objectProperties) { var item = PropertyAccessor.Get(root.GetType(), root, property.Name); if (item is T && !ancestors.Contains((T)item)) { action(root, (T)item); CascadeImplementation((T)item, action, ancestors); } } foreach (var property in collectionProperties) { var items = (IEnumerable)PropertyAccessor.Get(root.GetType(), root, property.Name); if (items != null) { foreach (var item in items) { if (item is T && !ancestors.Contains((T)item)) { action(root, (T)item); CascadeImplementation((T)item, action, ancestors); } } } } }
public object GetCurrentChildValue() => PropertyAccessor.Get(Father.CValue);
public ValuedUpdateBuilder <T> Set <TColumn>(Expression <Func <T, TColumn> > column, TColumn value) { ((IValuedUpdateBuilder <T>) this).Set(PropertyAccessor.Get(column), value); return(this); }
private static void MergeCollectionProperties(DbContext context, object source, object target, IEqualityComparer <object> comparer, HashSet <object> ancestors, IReadOnlyCollection <string[]> paths, int level, PropertyInfo[] properties) { foreach (var property in properties.Where(p => p.PropertyType != typeof(string) && p.PropertyType.IsGenericType && typeof(IEnumerable).IsAssignableFrom(p.PropertyType))) { var colletionProperty = context.Entry(target).Collection(property.Name); if (colletionProperty == null) { continue; } var collection = colletionProperty.CurrentValue as IList; var values = ((IEnumerable)PropertyAccessor.Get(target.GetType(), target, property.Name) ?? new object[] { }).Cast <object>().ToList(); var newValues = ((IEnumerable)PropertyAccessor.Get(source.GetType(), source, property.Name) ?? new object[] { }).Cast <object>().ToList(); var updates = newValues.Join(values, comparer.GetHashCode, comparer.GetHashCode, Tuple.Create).ToList(); foreach (var item in updates) { if (ancestors.Contains(item)) { continue; } var entry = context.Entry(item.Item2); switch (entry.State) { case EntityState.Detached: { var hash = comparer.GetHashCode(item.Item2); var attachedTarget = context.Set(item.Item2.GetType()).Local.Cast <object>().FirstOrDefault(e => comparer.GetHashCode(e) == hash); if (attachedTarget != null) { entry = context.Entry(attachedTarget); entry.CurrentValues.SetValues(item.Item1); } } break; case EntityState.Unchanged: entry.CurrentValues.SetValues(item.Item1); break; } MergeImplementation(context, item.Item1, item.Item2, comparer, new HashSet <object>(ancestors), paths, level + 1); } var deletes = values.Except(newValues, comparer).ToList(); foreach (var item in deletes) { if (ancestors.Contains(item)) { continue; } if (collection == null) { continue; } collection.Remove(item); context.Entry(item).State = EntityState.Deleted; } var inserts = newValues.Where(e => !values.Any(f => comparer.Equals(e, f))).ToList(); foreach (var item in inserts) { if (ancestors.Contains(item)) { continue; } if (collection == null) { continue; } collection.Add(item); var entry = context.Entry(item); var objectProperties = item.GetType().GetProperties().Where(p => p.PropertyType.IsClass && p.PropertyType != typeof(string)); foreach (var objectProperty in objectProperties) { var member = entry.Member(objectProperty.Name); if (member == null || member.EntityEntry.State != EntityState.Detached || member.CurrentValue == null) { continue; } var hash = comparer.GetHashCode(member.CurrentValue); var local = context.Set(member.CurrentValue.GetType()).Local.Cast <object>().FirstOrDefault(e => comparer.GetHashCode(e) == hash); if (local != null && local != member.CurrentValue) { // Found unchanged locally // Assign existing parent PropertyAccessor.Set(item.GetType(), item, objectProperty.Name, local); } } entry.State = EntityState.Added; } } }
public void Bind(object source) { if (source == null) { throw new ArgumentNullException("source"); } if (!NotifyPropertyChanged.IsInstanceOfType(source)) { Console.WriteLine("Error[{0}] does not implement INotifyPropertyChanged", source.GetType().FullName); } var injectables = from property in source.GetType().GetProperties() where property.CanRead && property.CanWrite && Attribute.IsDefined(property, typeof(BindAttribute)) select property; foreach (var propertyInfo in injectables) { var attribute = propertyInfo.GetCustomAttribute <BindAttribute>(); var converter = IoC.Get <IValueConverter>(attribute.Service.Name + "Converter"); object target = null; Console.WriteLine( "Bind[{0}] Property[{1}] Key[{2}] Service[{3}] Converter[{4}]", propertyInfo.Name, attribute.Property, attribute.Key, attribute.Service, converter); //if (EnumerableType.IsAssignableFrom(propertyInfo.PropertyType)) //{ // target = IoC.GetAll(attribute.Service, attribute.Key); //} //else { target = IoC.Get(attribute.Service, attribute.Key); } var sourceAccessor = new PropertyAccessor(source.GetType(), propertyInfo.Name); var targetAccessor = new PropertyAccessor(attribute.Service, attribute.Property ?? propertyInfo.Name); ((INotifyPropertyChanged)(target)).PropertyChanged += (sender, args) => { if (args.PropertyName == targetAccessor.Property) { var sourceValue = sourceAccessor.Get(source); var targetValue = targetAccessor.Get(target); if (sourceValue == null || !sourceValue.Equals(targetValue)) { Console.WriteLine( "Set[ {0} @ {1} ] {2} >>> {3}", args.PropertyName, sender.GetType().FullName, sourceValue, targetValue); sourceAccessor.Set(source, targetValue); } } }; ((INotifyPropertyChanged)(source)).PropertyChanged += (sender, args) => { if (args.PropertyName == sourceAccessor.Property) { var sourceValue = sourceAccessor.Get(source); var targetValue = targetAccessor.Get(target); if (sourceValue == null || !sourceValue.Equals(targetValue)) { Console.WriteLine( "Set[ {0} @ {1} ] {2} >>> {3}", args.PropertyName, sender.GetType().FullName, targetValue, sourceValue); targetAccessor.Set(target, sourceValue); } } }; } }
object[] IMetaDataProvider.GetPrimaryKeyValue <T>(T entity) { var idPropertyName = _context.Session.Client.Infer.Id(entity); return(new[] { PropertyAccessor.Get(entity, idPropertyName) }); }
object[] IMetaDataProvider.GetPrimaryKeyValue <T>(T entity) { var key = ((IMetaDataProvider)this).GetPrimaryKey <T>().First(); return(new [] { PropertyAccessor.Get(entity, key) }); }
internal ColumnMap(Expression <Func <T, byte[]?> > column, int length) : this(PropertyAccessor.Get(column)) { Length = length; }
internal ColumnMap(Expression <Func <T, double?> > column, int precision, int scale) : this(PropertyAccessor.Get(column)) { Precision = precision; Scale = scale; }