简体   繁体   English

C# 引用类型(即“out”参数) typeof(char &) 或 typeof(out char)

[英]C# type of references (i,.e. "out" parameters) typeof(char &) or typeof(out char)

For some library debugging usage I am developing a custom attribute which whould be able to match existing methods.对于某些库调试用途,我正在开发一个自定义属性,该属性应该能够匹配现有方法。

For example the following:例如以下:

[NetMethodAliasMethod("TryParse", Parameters = new Type[] { typeof(string), typeof(char)})]

...should match static bool System.Char.TryParse (string? s, out char result) . ...应该匹配 static bool System.Char.TryParse (string? s, out char result) The attribute "Parameters" are tested against ParameterInfo.ParameterType MethodInfo.GetParameters() to match the parameters (of course name is matched as well).针对 ParameterInfo.ParameterType MethodInfo.GetParameters() 测试属性“Parameters”以匹配参数(当然名称也匹配)。

In case of the string?如果是string? this works because the nullable attribute is not part of the type.这是有效的,因为可空属性不是类型的一部分。 However the type returned from MethodInfo for the 2nd parameter is char& , while typeof(char&) is not allowed.但是,从MethodInfo返回的第二个参数的类型是char& ,而typeof(char&)是不允许的。 Is there any possible way to pass this type?有没有可能通过这种类型的方法?

I was thinking about generic delegates, but see no way as the use of delegates is to be specific on which methods are compatible.我正在考虑泛型委托,但看不到任何方法,因为委托的使用要具体说明哪些方法是兼容的。 Another Idea was to use typeof(System.Char).GetMethod("TryParse") .另一个想法是使用typeof(System.Char).GetMethod("TryParse") But this causes the same trouble if multiple overloads exist, where we would have to use GetMethods (with 's') instead and again match the paramater types.但是,如果存在多个重载,这会导致同样的麻烦,我们将不得不使用GetMethods (带有 's'),并再次匹配参数类型。

Of course I could use string checking of the type names, but that should be the last resort if no other way is possible.当然,我可以使用类型名称的字符串检查,但如果没有其他方法,那应该是最后的手段。 But since Type(char&) exists, I hope there is a way to get it?但是既然Type(char&)存在,我希望有办法得到它吗?

You can make such a type by using the MakeByRefType method.您可以使用MakeByRefType方法创建这样的类型。

However you cannot actually call this method when writing your attribute, because something like typeof(int).MakeByRefType() is not an attribute argument expression (defined at the very bottom of this section ).但是,您在编写属性时实际上不能调用此方法,因为typeof(int).MakeByRefType()类的东西不是属性参数表达式(在本节的最底部定义)。

Therefore, a workaround I would go for is to declare an additional parameter for your attribute that encodes where these "by refs" are:因此,我会 go 的解决方法是为您的属性声明一个附加参数,该参数编码这些“by refs”的位置:

public bool[] ParametersAreByRef { get; set; }

And then do:然后做:

[NetMethodAliasMethod(
    "TryParse", 
    Parameters = new Type[] { typeof(string), typeof(char)}
    ParametersAreByRef = new bool[] { false, true })]

Only when you retrieve the attribute later down the line, do you use MakeByRefType to recreate the Type s depending on the values in ParametersAreByRef .只有当您稍后检索该属性时,您才会使用MakeByRefType根据ParametersAreByRef中的值重新创建Type

var modifiedParameters = attribute.Parameters.Zip(
    attribute.ParametersAreByRef, (t, b) => b ? t.MakeByRefType() : t
).ToArray()

If you don't like passing ParametersAreByRef every time for methods with all non-by-ref parameters, you can make Parameters a positional parameter (put it as a constructor parameter), and then you can initialise ParametersAreByRef to Parameters.Select(x => false).ToArray() by default or something like that in the constructor.如果您不喜欢每次都为所有非按引用参数的方法传递ParametersAreByRef ,您可以将Parameters设置为位置参数(将其作为构造函数参数),然后您可以将ParametersAreByRef初始化为Parameters.Select(x => false).ToArray()默认情况下或构造函数中的类似内容。

As Jeroen Mostert suggested in the comments, another workaround is to use pointer types, seeing as they are very rare in actual code, to encode by-ref-ness:正如 Jeroen Mostert 在评论中所建议的那样,另一种解决方法是使用指针类型,因为它们在实际代码中非常罕见,因此对按引用进行编码:

Parameters = new Type[] { typeof(string), typeof(char*)}

When you retrieve the attribute instance, check IsPointer and use GetElementType :当您检索属性实例时,检查IsPointer并使用GetElementType

var modifiedParameters = attribute.Parameters.Select(
    x => x.IsPointer ? x.GetElementType().MakeByRefType() : x
).ToArray();

You can also do this in the setter of Parameters if it has a backing field.如果有支持字段,您也可以在Parameters设置器中执行此操作。

Alternatively, make your own dummy ByRef<T> type so that by-ref-ness can be annotated:或者,制作您自己的虚拟ByRef<T>类型,以便可以注释 by-ref-ness:

public abstract class ByRef<T> {}

…

Parameters = new Type[] { typeof(string), typeof(ByRef<char>)}

Then然后

// e.g. in the setter of Parameters
_parameters = Parameters.Select(
    x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(ByRef<>) ? x.GetGenericArguments()[0].MakeByRefType() : x
).ToArray();

I like the elegance of @JeroenMostert comment so I did add a ByRef abstract generic class to my attribute:我喜欢@JeroenMostert 评论的优雅,所以我在我的属性中添加了一个 ByRef 抽象通用 class :

public abstract class ByRef<T> { };

and modified the Parameters property to resolve the type并修改了Parameters属性来解析类型

private Type[]? _parameters = null;
public Type[]? Parameters
{
  get { return _parameters; }
  set
  {
    if(value==null)
    {
      _parameters = null;
      return;
    }

    for(int i=0; i<value.Length; i++)
    {
      Type type = value[i];

      if(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ByRef<>))
      {
        value[i] = type.GetGenericArguments()[0].MakeByRefType();
      }

      _parameters = value;
    }
  }
}

This setter resolves all ByRef to T&此设置器将所有 ByRef 解析为 T&

Note that in my case here, Parameters is nullable because I use null as parameter wildcard (ie matching any types and count).请注意,在我的例子中, Parameters可以为空,因为我使用 null 作为参数通配符(即匹配任何类型和计数)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM