gpt4 book ai didi

c# - 检查构造函数是否调用另一个构造函数

转载 作者:太空狗 更新时间:2023-10-29 23:16:59 24 4
gpt4 key购买 nike

在反射过程中,在 C# 中是否可以检查一个构造函数是否调用另一个构造函数?

class Test
{
public Test() : this( false ) { }
public Test( bool inner ) { }
}

我想确定每个 ConstructorInfo无论它是否在调用链的末尾。

最佳答案

这是一个临时答案,用于陈述我目前的发现。

我没有找到 ConstructorInfo 的任何属性,它可以指示构造函数是否调用另一个构造函数。 MethodBody 的属性也没有.

我在评估 MSIL 字节代码方面取得了一些成功。我的第一个发现表明,最终调用的构造函数立即以 OpCodes.Call 开始,除了一些可能的其他 OpCodes。调用其他构造函数的构造函数具有“意外的”OpCodes

public static bool CallsOtherConstructor( this ConstructorInfo constructor )
{
MethodBody body = constructor.GetMethodBody();
if ( body == null )
{
throw new ArgumentException( "Constructors are expected to always contain byte code." );
}

// Constructors at the end of the invocation chain start with 'call' immediately.
var untilCall = body.GetILAsByteArray().TakeWhile( b => b != OpCodes.Call.Value );
return !untilCall.All( b =>
b == OpCodes.Nop.Value || // Never encountered, but my intuition tells me a no-op would be valid.
b == OpCodes.Ldarg_0.Value || // Seems to always precede Call immediately.
b == OpCodes.Ldarg_1.Value // Seems to be added when calling base constructor.
);
}

我完全不确定 MSIL。也许不可能在两者之间没有任何操作,或者根本不需要启动这样的构造函数,但对于我当前的所有单元测试,它似乎都有效。

[TestClass]
public class ConstructorInfoExtensionsTest
{
class PublicConstructors
{
// First
public PublicConstructors() : this( true ) {}

// Second
public PublicConstructors( bool one ) : this( true, true ) {}

// Final
public PublicConstructors( bool one, bool two ) {}

// Alternate final
public PublicConstructors( bool one, bool two, bool three ) {}
}

class PrivateConstructors
{
// First
PrivateConstructors() : this( true ) {}

// Second
PrivateConstructors( bool one ) : this( true, true ) {}

// Final
PrivateConstructors( bool one, bool two ) {}

// Alternate final
PrivateConstructors( bool one, bool two, bool three ) {}
}

class TripleBaseConstructors : DoubleBaseConstructors
{
public TripleBaseConstructors() : base() { }
public TripleBaseConstructors( bool one ) : base( one ) { }
}

class DoubleBaseConstructors : BaseConstructors
{
public DoubleBaseConstructors() : base() {}
public DoubleBaseConstructors( bool one ) : base( one ) {}
}

class BaseConstructors : Base
{
public BaseConstructors() : base() {}
public BaseConstructors( bool one ) : base( one ) {}
}

class Base
{
// No parameters
public Base() {}

// One parameter
public Base( bool one ) {}
}

class ContentConstructor
{
public ContentConstructor()
{
SomeMethod();
}

public ContentConstructor( bool one )
{
int bleh = 0;
}

bool setTwo;
public ContentConstructor( bool one, bool two )
{
setTwo = two;
}

void SomeMethod() {}
}

[TestMethod]
public void CallsOtherConstructorTest()
{
Action<ConstructorInfo[]> checkConstructors = cs =>
{
ConstructorInfo first = cs.Where( c => c.GetParameters().Count() == 0 ).First();
Assert.IsTrue( first.CallsOtherConstructor() );
ConstructorInfo second = cs.Where( c => c.GetParameters().Count() == 1 ).First();
Assert.IsTrue( second.CallsOtherConstructor() );
ConstructorInfo final = cs.Where( c => c.GetParameters().Count() == 2 ).First();
Assert.IsFalse( final.CallsOtherConstructor() );
ConstructorInfo alternateFinal = cs.Where( c => c.GetParameters().Count() == 3 ).First();
Assert.IsFalse( alternateFinal.CallsOtherConstructor() );
};

// Public and private constructors.
checkConstructors( typeof( PublicConstructors ).GetConstructors() );
checkConstructors( typeof( PrivateConstructors ).GetConstructors( BindingFlags.NonPublic | BindingFlags.Instance ) );

// Inheritance.
Action<ConstructorInfo[]> checkBaseConstructors = cs =>
{
ConstructorInfo noParameters = cs.Where( c => c.GetParameters().Count() == 0 ).First();
ConstructorInfo oneParameter = cs.Where( c => c.GetParameters().Count() == 1 ).First();

// Only interested in constructors specified on this type, not base constructors,
// thus calling a base constructor shouldn't qualify as 'true'.
Assert.IsFalse( noParameters.CallsOtherConstructor() );
Assert.IsFalse( oneParameter.CallsOtherConstructor() );
};
checkBaseConstructors( typeof( BaseConstructors ).GetConstructors() );
checkBaseConstructors( typeof( DoubleBaseConstructors ).GetConstructors() );
checkBaseConstructors( typeof( TripleBaseConstructors ).GetConstructors() );

// Constructor with content.
foreach( var constructor in typeof( ContentConstructor ).GetConstructors() )
{
Assert.IsFalse( constructor.CallsOtherConstructor() );
}
}
}

关于c# - 检查构造函数是否调用另一个构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9848954/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com