-
Notifications
You must be signed in to change notification settings - Fork 119
Конвертеры CLR-BSL #1566
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Конвертеры CLR-BSL #1566
Changes from 7 commits
7c6e30e
8f8badf
b70bc6e
246c18b
2c193be
bed0b39
36af65e
55eeeb3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ This Source Code Form is subject to the terms of the | |
| using System.Linq; | ||
| using System.Reflection; | ||
| using OneScript.Commons; | ||
| using ScriptEngine.Machine; | ||
|
|
||
| namespace OneScript.Contexts | ||
| { | ||
|
|
@@ -20,7 +21,7 @@ public class ContextPropertyInfo : BslPropertyInfo, IObjectWrapper | |
| { | ||
| private readonly PropertyInfo _realProperty; | ||
| private readonly ContextPropertyAttribute _scriptMark; | ||
|
|
||
| public ContextPropertyInfo(PropertyInfo wrappedInfo) | ||
| { | ||
| _realProperty = wrappedInfo; | ||
|
|
@@ -54,6 +55,32 @@ public override bool Equals(BslPropertyInfo other) | |
|
|
||
| public override string Alias => _scriptMark.Alias; | ||
|
|
||
| public Type ConverterType => _scriptMark.Converter; | ||
|
|
||
| public bool TryGetConverter(out object converter) | ||
| { | ||
| if (ConverterType == null) | ||
| { | ||
| converter = null; | ||
| return false; | ||
| } | ||
|
|
||
| converter = Activator.CreateInstance(ConverterType); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Не совсем понял, какой смысл в этом методе, что если я укажу в атрибуте в качестве конвертера typeof(Int32) и получу тут число? Может он должен быть private? |
||
| return true; | ||
| } | ||
|
|
||
| public bool TryGetStrictConverter<T>(out IContextValueConverter<T> converter) | ||
| { | ||
| var result = TryGetConverter(out var c); | ||
|
|
||
| if (result) | ||
| converter = c as IContextValueConverter<T>; | ||
| else | ||
| converter = null; | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| public override MethodInfo[] GetAccessors(bool nonPublic) | ||
| { | ||
| var getter = GetGetMethod(nonPublic); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| /*---------------------------------------------------------- | ||
| This Source Code Form is subject to the terms of the | ||
| Mozilla Public License, v.2.0. If a copy of the MPL | ||
| was not distributed with this file, You can obtain one | ||
| at http://mozilla.org/MPL/2.0/. | ||
| ----------------------------------------------------------*/ | ||
| using System; | ||
| using System.Linq; | ||
| using ScriptEngine.Machine; | ||
|
|
||
| namespace OneScript.Contexts | ||
| { | ||
| public interface IContextValueConverter<TClr> | ||
| { | ||
| IValue ToIValue(TClr obj); | ||
|
|
||
| TClr ToClr(IValue obj); | ||
|
|
||
| public static bool ImplementsIt(Type type) | ||
| => type.GetInterfaces() | ||
| .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IContextValueConverter<>)); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,8 +16,8 @@ namespace ScriptEngine.Machine.Contexts | |
| { | ||
| public class PropertyTarget<TInstance> | ||
| { | ||
| private readonly BslPropertyInfo _propertyInfo; | ||
|
|
||
| private readonly ContextPropertyInfo _propertyInfo; | ||
| public PropertyTarget(PropertyInfo propInfo) | ||
| { | ||
| _propertyInfo = new ContextPropertyInfo(propInfo); | ||
|
|
@@ -27,16 +27,6 @@ public PropertyTarget(PropertyInfo propInfo) | |
| if (string.IsNullOrEmpty(Alias)) | ||
| Alias = propInfo.Name; | ||
|
|
||
| IValue CantReadAction(TInstance inst) | ||
| { | ||
| throw PropertyAccessException.PropIsNotReadableException(Name); | ||
| } | ||
|
|
||
| void CantWriteAction(TInstance inst, IValue val) | ||
| { | ||
| throw PropertyAccessException.PropIsNotWritableException(Name); | ||
| } | ||
|
|
||
| if (_propertyInfo.CanRead) | ||
| { | ||
| var getMethodInfo = propInfo.GetGetMethod(); | ||
|
|
@@ -84,6 +74,18 @@ void CantWriteAction(TInstance inst, IValue val) | |
| { | ||
| Setter = CantWriteAction; | ||
| } | ||
|
|
||
| return; | ||
|
|
||
| void CantWriteAction(TInstance inst, IValue val) | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. а чем помешали в качестве локальных методов? |
||
| { | ||
| throw PropertyAccessException.PropIsNotWritableException(Name); | ||
| } | ||
|
|
||
| IValue CantReadAction(TInstance inst) | ||
| { | ||
| throw PropertyAccessException.PropIsNotReadableException(Name); | ||
| } | ||
| } | ||
|
|
||
| public Func<TInstance, IValue> Getter { get; } | ||
|
|
@@ -108,19 +110,18 @@ private Func<TInstance, IValue> CreateGetter<T>(MethodInfo methInfo) | |
| private Action<TInstance, IValue> CreateSetter<T>(MethodInfo methInfo) | ||
| { | ||
| var method = (Action<TInstance, T>)Delegate.CreateDelegate(typeof(Action<TInstance, T>), methInfo); | ||
| return (inst, val) => method(inst, ConvertParam<T>(val)); | ||
| return (inst, val) => method(inst, ConvertValue<T>(val)); | ||
| } | ||
|
|
||
| private static T ConvertParam<T>(IValue value) | ||
| { | ||
| return ContextValuesMarshaller.ConvertValueStrict<T>(value); | ||
| } | ||
|
|
||
| private static IValue ConvertReturnValue<TRet>(TRet param) | ||
| { | ||
| return ContextValuesMarshaller.ConvertReturnValue(param); | ||
| } | ||
| private T ConvertValue<T>(IValue value) | ||
| => _propertyInfo.TryGetStrictConverter<T>(out var converter) ? | ||
| converter.ToClr(value) | ||
| : ContextValuesMarshaller.ConvertValueStrict<T>(value); | ||
|
|
||
| private IValue ConvertReturnValue<TRet>(TRet param) | ||
| => _propertyInfo.TryGetStrictConverter<TRet>(out var converter) | ||
| ? converter!.ToIValue(param) | ||
| : ContextValuesMarshaller.ConvertReturnValue(param); | ||
| } | ||
|
|
||
| public class ContextPropertyMapper<TInstance> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
TryGetConverter can throw; enforce “Try” semantics and validate type viability*
Activator.CreateInstance will throw for abstract types, open generics, or when no public parameterless ctor exists. A Try* method should not throw. Guard and catch, returning false.
public bool TryGetConverter(out object converter) { if (ConverterType == null) { converter = null; return false; } - - converter = Activator.CreateInstance(ConverterType); - return true; + + try + { + if (ConverterType.IsAbstract || ConverterType.IsInterface || ConverterType.ContainsGenericParameters) + { + converter = null; + return false; + } + + if (ConverterType.GetConstructor(Type.EmptyTypes) == null) + { + converter = null; + return false; + } + + converter = Activator.CreateInstance(ConverterType); + return converter != null; + } + catch (Exception) + { + converter = null; + return false; + } }Optional: if converters are stateless, consider caching a single instance per ContextMethodInfo to reduce allocations. Happy to propose a thread-safe cache if desired.
📝 Committable suggestion
🤖 Prompt for AI Agents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@akpaevj может есть какой-то способ запретить указывать абстрактный тип в атрибуте? Ну или можно забить...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.