Skip to content

Commit

Permalink
DispId(0) for Value-Property (#321)
Browse files Browse the repository at this point in the history
* State

* Fixed IndexParameter

* CodeReview
  • Loading branch information
mavToday authored Jan 3, 2025
1 parent 171fa7f commit 2b4369a
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 115 deletions.
79 changes: 11 additions & 68 deletions src/dscom.test/builder/DynamicMethodBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,6 @@ namespace dSPACE.Runtime.InteropServices.Tests;

internal sealed class DynamicMethodBuilder : DynamicBuilder<DynamicMethodBuilder>
{
internal record struct DefaultValue(
object? Value
);

internal record struct ParameterItem(
Type Type,
ParameterAttributes? ParameterAttributes,
DefaultValue? DefaultValue = null
);

public DynamicMethodBuilder(DynamicTypeBuilder dynamicTypeBuilder, string name) : base(name)
{
DynamicTypeBuilder = dynamicTypeBuilder;
Expand All @@ -37,14 +27,10 @@ public DynamicMethodBuilder(DynamicTypeBuilder dynamicTypeBuilder, string name)

private Tuple<Type, object>? ReturnTypeAttribute { get; set; }

public List<ParameterItem> ParamterItems { get; } = new();

public Tuple<Type, object?>[]? ParamAttributes { get; set; }

public Dictionary<int, Tuple<FieldInfo[], object?[]>> ParamAttributesFieldValues { get; set; } = new();

protected override AttributeTargets AttributeTarget => AttributeTargets.Method;

private readonly DynamicParameterBuilder _parameterBuilder = new();

public DynamicMethodBuilder WithReturnType(Type type)
{
ReturnType = type;
Expand All @@ -64,13 +50,13 @@ public DynamicMethodBuilder WithParameter<T>()

public DynamicMethodBuilder WithParameter(Type parameterType)
{
ParamterItems.Add(new ParameterItem(parameterType, null));
_parameterBuilder.AddParameter(new ParameterItem(parameterType, null));
return this;
}

public DynamicMethodBuilder WithParameter(ParameterItem parameterItem)
{
ParamterItems.Add(parameterItem);
_parameterBuilder.AddParameter(parameterItem);
return this;
}

Expand All @@ -82,34 +68,27 @@ public DynamicMethodBuilder WithReturnTypeCustomAttribute<T>(object value)

public DynamicMethodBuilder WithParameterCustomAttribute<T>(int parameterIndex)
{
var attributes = ParamAttributes ?? new Tuple<Type, object?>[ParamterItems == null ? 0 : ParamterItems.Count];
attributes[parameterIndex] = new(typeof(T), null);
ParamAttributes = attributes;
return this;
return WithParameterCustomAttribute<T>(parameterIndex, null);
}

public DynamicMethodBuilder WithParameterCustomAttribute<T>(int parameterIndex, object value)
public DynamicMethodBuilder WithParameterCustomAttribute<T>(int parameterIndex, object? value)
{
var attributes = ParamAttributes ?? new Tuple<Type, object?>[ParamterItems == null ? 0 : ParamterItems.Count];
attributes[parameterIndex] = new(typeof(T), value);
ParamAttributes = attributes;
_parameterBuilder.AddParameterAttribute<T>(parameterIndex, value);
return this;
}

public DynamicMethodBuilder WithParameterCustomAttribute<T>(int parameterIndex, object value, FieldInfo[] namedFields, object?[] fieldValues)
{
var attributes = ParamAttributes ?? new Tuple<Type, object?>[ParamterItems == null ? 0 : ParamterItems.Count];
attributes[parameterIndex] = new(typeof(T), value);
ParamAttributes = attributes;
ParamAttributesFieldValues[parameterIndex] = new(namedFields, fieldValues);
_parameterBuilder.AddParameterAttribute<T>(parameterIndex, value);
_parameterBuilder.AddParameterCustomAttributeFieldValue(parameterIndex, namedFields, fieldValues);
return this;
}

public DynamicTypeBuilder CreateMethod()
{
var methodBuilder = DynamicTypeBuilder.TypeBuilder!.DefineMethod(Name,
MethodAttributes.Abstract | MethodAttributes.Public | MethodAttributes.Virtual,
CallingConventions.HasThis, ReturnType, ParamterItems.Select(p => p.Type).ToArray());
CallingConventions.HasThis, ReturnType, _parameterBuilder.GetParameterTypes());

var returnParamBuilder = methodBuilder.DefineParameter(0, ParameterAttributes.Retval, null);
if (ReturnTypeAttribute != null)
Expand All @@ -123,43 +102,7 @@ public DynamicTypeBuilder CreateMethod()
returnParamBuilder.SetCustomAttribute(attributeBuilder);
}

var index = 1;

foreach (var item in ParamterItems)
{
var hasDefaultValue = item.DefaultValue != null;

var parameterAttribute = item.ParameterAttributes;
parameterAttribute ??= hasDefaultValue ? ParameterAttributes.HasDefault : ParameterAttributes.None;

var paramBuilder = methodBuilder.DefineParameter(index, parameterAttribute.Value, $"Param{index}");
if (ParamAttributes != null)
{
//use parameter attributes
if ((ParamAttributes.Length > index - 1) && ParamAttributes.GetValue(index - 1) != null)
{
var attributeParam = ParamAttributes[index - 1].Item2;
var typeAttributeParam = ParamAttributes[index - 1].Item2 == null ? typeof(object) : ParamAttributes[index - 1].Item2?.GetType();
var typeAttribute = ParamAttributes[index - 1].Item1;

var attributeConstructor = attributeParam != null && typeAttributeParam != null ? typeAttribute.GetConstructor(new Type[] { typeAttributeParam }) : typeAttribute.GetConstructor(Array.Empty<Type>());

ParamAttributesFieldValues.TryGetValue(index - 1, out var fields);

var attributeBuilder = attributeParam == null
? new CustomAttributeBuilder(attributeConstructor!, Array.Empty<object>())
: fields != null
? new CustomAttributeBuilder(attributeConstructor!, new object[] { attributeParam }, fields.Item1, fields.Item2)
: new CustomAttributeBuilder(attributeConstructor!, new object[] { attributeParam });
paramBuilder.SetCustomAttribute(attributeBuilder);
}
}
if (hasDefaultValue)
{
paramBuilder.SetConstant(item.DefaultValue!.Value.Value);
}
index++;
}
_parameterBuilder.AddParameters(methodBuilder);

foreach (var customAttributeBuilder in CustomAttributeBuilder)
{
Expand Down
99 changes: 99 additions & 0 deletions src/dscom.test/builder/DynamicParameterBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2022 dSPACE GmbH, Mark Lechtermann, Matthias Nissen and Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace dSPACE.Runtime.InteropServices.Tests;

internal record struct DefaultValue(
object? Value
);

internal record struct ParameterItem(
Type Type,
ParameterAttributes? ParameterAttributes,
DefaultValue? DefaultValue = null
);

internal sealed class DynamicParameterBuilder
{
public int Count => _parameterItems.Count;

private readonly List<ParameterItem> _parameterItems = new();

private Tuple<Type, object?>[]? _paramAttributes;

private readonly Dictionary<int, Tuple<FieldInfo[], object?[]>> _paramAttributesFieldValues = new();

public void AddParameterAttribute<T>(int parameterIndex, object? value)
{
var attributes = _paramAttributes ?? new Tuple<Type, object?>[_parameterItems == null ? 0 : _parameterItems.Count];
attributes[parameterIndex] = new(typeof(T), value);
_paramAttributes = attributes;
}

public void AddParameterCustomAttributeFieldValue(int parameterIndex, FieldInfo[] namedFields, object?[] fieldValues)
{
_paramAttributesFieldValues[parameterIndex] = new(namedFields, fieldValues);
}

public Type[] GetParameterTypes()
{
return _parameterItems.Select(p => p.Type).ToArray();
}
public void AddParameter(ParameterItem parameter)
{
_parameterItems.Add(parameter);
}

public void AddParameters(MethodBuilder methodBuilder, int index = 1)
{
for (var iParameter = 0; iParameter < _parameterItems.Count; iParameter++)
{
var item = _parameterItems[iParameter];

var hasDefaultValue = item.DefaultValue != null;

var parameterAttribute = item.ParameterAttributes;
parameterAttribute ??= hasDefaultValue ? ParameterAttributes.HasDefault : ParameterAttributes.None;

var paramBuilder = methodBuilder.DefineParameter(index, parameterAttribute.Value, $"Param{index}");
if (_paramAttributes != null)
{
//use parameter attributes
if ((_paramAttributes.Length > iParameter) && _paramAttributes.GetValue(iParameter) != null)
{
var attributeParam = _paramAttributes[iParameter].Item2;
var typeAttributeParam = _paramAttributes[iParameter].Item2 == null ? typeof(object) : _paramAttributes[iParameter].Item2?.GetType();
var typeAttribute = _paramAttributes[iParameter].Item1;

var attributeConstructor = attributeParam != null && typeAttributeParam != null ? typeAttribute.GetConstructor(new Type[] { typeAttributeParam }) : typeAttribute.GetConstructor(Array.Empty<Type>());

_paramAttributesFieldValues.TryGetValue(iParameter, out var fields);

var attributeBuilder = attributeParam == null
? new CustomAttributeBuilder(attributeConstructor!, Array.Empty<object>())
: fields != null
? new CustomAttributeBuilder(attributeConstructor!, new object[] { attributeParam }, fields.Item1, fields.Item2)
: new CustomAttributeBuilder(attributeConstructor!, new object[] { attributeParam });
paramBuilder.SetCustomAttribute(attributeBuilder);
}
}
if (hasDefaultValue)
{
paramBuilder.SetConstant(item.DefaultValue!.Value.Value);
}

index++;
}
}
}
Loading

0 comments on commit 2b4369a

Please sign in to comment.