[C#] 型が同一アセンブリ内 internal アクセスできるか判定する
外部アセンブリからアクセスできる型かどうかの public
判定は Type.IsVisibleで可能で、Assembly.GetExportedTypes() で全てのパブリック型を取得できる。
この internal
版の判定を行いたい。public
, internal
, protected internal
で入れ子になったネスト型も含めて、同一アセンブリ内でアクセスできるかどうかを判定する。
ここでは protected
による継承でアクセスできるかどうかは判定対象外とする。
環境
- .NET 6.0.101
- C# 10.0
- Visual Studio 2022 Version 17.0.5
- Windows 10 Pro 64bit 21H1 19043.1466
結果
使用方法
// internal アクセス可能な型を判定 (Type.IsVisible の internal 版)
var isInternalVisible = this.GetType().IsInternalVisible();
// internal アクセス可能な型を全て取得 (Assembly.GetExportedTypes() の internal 版)
var types = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(x => x.IsInternalVisible())
.ToArray();
実装
public static class TypeAccessibilityExtensions
{
public static bool IsInternalVisible(this Type type)
{
return type.GetAccessibility() == Accessibility.Internal;
}
private static Accessibility GetAccessibility(this Type type)
{
// public
if (type.IsVisible)
return Accessibility.Public;
// public or internal
var accessibility = GetCore(type);
if (accessibility == Accessibility.None)
return Accessibility.None;
if (!type.IsNested)
return accessibility;
// Nested
var declaringType = type.DeclaringType;
while (declaringType is not null)
{
accessibility = GetCore(declaringType) switch
{
Accessibility.Public => accessibility,
Accessibility.Internal => Accessibility.Internal,
_ => Accessibility.None,
};
if (accessibility == Accessibility.None)
return Accessibility.None;
declaringType = declaringType.DeclaringType;
}
return accessibility;
static Accessibility GetCore(Type type)
{
if (type.IsPublic || type.IsNestedPublic)
return Accessibility.Public;
if (type.IsNotPublic || type.IsNestedAssembly || type.IsNestedFamORAssem)
return Accessibility.Internal;
return Accessibility.None;
}
}
private enum Accessibility
{
None,
Public,
Internal,
}
}
説明
まず、外部アセンブリからアクセス可能な public 判定は Type.IsVisible で判定する。
ネストされていないトップレベル型も、ネストされている型も考慮されて判定できる。
判定方法 | アクセスレベル |
---|---|
Type.IsVisible | public |
次にネストされていないトップレベル型の判定方法であるが、
ネストされていない型は public
, internal
のみ定義可能であり、protected internal
, private
, private protected
は定義不可であるため、以下2パターンで判定する。
判定方法 | アクセスレベル |
---|---|
Type.IsPublic | public |
Type.IsNotPublic | internal |
次にネストされている型の場合は、IsNested
が付くプロパティで判定する。
判定方法 | アクセスレベル |
---|---|
Type.IsNestedPublic | public |
Type.IsNestedAssembly | internal |
Type.IsNestedFamORAssem | protected internal |
上記で判定できるのはネスト型自身に定義されたアクセス修飾子であるため、ネスト型を包含する型の親階層を全て調べて判断する必要がある。
例えば、ネスト型が internal
でもそのネストの親階層の型が private
であれば internal
と判定しない。
包含したネスト親の型は Type.DeclaringType で取得できる。
また、Type.ReflectedType でも取得できるが、結果は DeclaringType
と同じとのこと。
注釈
オブジェクトの場合 Type 、このプロパティの値は常にプロパティの値と同じです DeclaringType 。
(参考) .NET ソース
public override Type? ReflectedType => DeclaringType;
説明をまとめると、以下のようになる。
private static Accessibility GetAccessibility(this Type type)
{
// 外部アセンブリからアクセス可能な public 判定 (トップレベル型、ネスト型どちらも考慮済み)
if (Type.IsVisible)
return Accessibility.Public;
// トップレベル型 (public or internal)
// or
// ネスト型 (public or internal or protected internal)
// の判定
var accessibility = GetCore(type);
// 自身が public or internal のアクセス許可していなければ return
if (accessibility == Accessibility.None)
return Accessibility.None;
// トップレベル型であれば、public or internal が確定するので return
if (!type.IsNested)
return accessibility;
// ネスト型では包含する型の親階層をトップレベル型まで調べていく
var declaringType = type.DeclaringType;
// トップレベル型まで調べたらループ終了
while (declaringType is not null)
{
// 包含するネスト親の型のアクセス判定
accessibility = GetCore(declaringType) switch
{
// 親が public なら自身のアクセスレベルが適用される (public or internal)
Accessibility.Public => accessibility,
// 親が internal なら自身が public でも internal アクセスに制限される (internal)
Accessibility.Internal => Accessibility.Internal,
// 親が internal 許可していない
_ => Accessibility.None,
};
// 親が public or internal 許可していなければ終了
if (accessibility == Accessibility.None)
return Accessibility.None;
// さらに包含する親の型がいるか調べる
declaringType = declaringType.DeclaringType;
}
return accessibility;
static Accessibility GetCore(Type type)
{
// public アクセス修飾子で定義された型か判定
if (type.IsPublic || type.IsNestedPublic)
return Accessibility.Public;
// internal, protected internal アクセス修飾子で定義された型か判定
if (type.IsNotPublic || type.IsNestedAssembly || type.IsNestedFamORAssem)
return Accessibility.Internal;
// public, internal のアクセス許可がない型と判定
return Accessibility.None;
}
}
検証
検証ソース
AccessibilityClassLibrary1.dll (netstandard2.0)
namespace AccessibilityClassLibrary1
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum)]
public class TypeAccessibilityAttribute : Attribute
{
public Accessibility Accessibility { get; }
public bool IsPublic => Accessibility == Accessibility.Public;
public bool IsInternal => Accessibility == Accessibility.Internal;
public TypeAccessibilityAttribute(Accessibility accessibility = Accessibility.None)
{
Accessibility = accessibility;
}
}
public enum Accessibility
{
None,
// Private,
Public,
// Protected,
Internal,
// ProtectedOrInternal,
// ProtectedAndInternal,
}
public static class AccessibilityExtensions
{
public static bool IsInternalVisible(this Type type)
{
return type.GetAccessibility() == Accessibility.Internal;
}
public static Accessibility GetAccessibility(this Type type)
{
// public
if (type.IsVisible)
return Accessibility.Public;
// public or internal
var accessibility = GetCore(type);
if (accessibility == Accessibility.None)
return Accessibility.None;
if (!type.IsNested)
return accessibility;
// Nested
var declaringType = type.DeclaringType;
while (declaringType is not null)
{
accessibility = GetCore(declaringType) switch
{
Accessibility.Public => accessibility,
Accessibility.Internal => Accessibility.Internal,
_ => Accessibility.None,
};
if (accessibility == Accessibility.None)
return Accessibility.None;
declaringType = declaringType.DeclaringType;
}
return accessibility;
static Accessibility GetCore(Type type)
{
if (type.IsPublic || type.IsNestedPublic)
return Accessibility.Public;
if (type.IsNotPublic || type.IsNestedAssembly || type.IsNestedFamORAssem)
return Accessibility.Internal;
return Accessibility.None;
}
}
}
}
[TypeAccessibility(Accessibility.Public)]
public enum RootPublicEnum
{
}
[TypeAccessibility(Accessibility.Internal)]
internal enum RootInternalEnum
{
}
[TypeAccessibility(Accessibility.Public)]
public class RootPublicClass
{
[TypeAccessibility(Accessibility.Public)]
public enum PublicEnumNested
{
}
[TypeAccessibility(Accessibility.Internal)]
internal enum InternalEnumNested
{
}
[TypeAccessibility(Accessibility.Public)]
public class PublicNestedClass
{
[TypeAccessibility(Accessibility.Public)] public interface IPublicNested { }
[TypeAccessibility(Accessibility.Internal)] internal interface IInternalNested { }
}
protected class ProtectedNestedClass
{
public interface IPublicNested { }
internal interface IInternalNested { }
}
[TypeAccessibility(Accessibility.Internal)]
protected internal class ProtectedInternalNestedClass
{
[TypeAccessibility(Accessibility.Internal)] public interface IPublicNested { }
[TypeAccessibility(Accessibility.Internal)] internal interface IInternalNested { }
}
[TypeAccessibility(Accessibility.Internal)]
internal class InternalNestedClass
{
[TypeAccessibility(Accessibility.Internal)] public interface IPublicNested { }
[TypeAccessibility(Accessibility.Internal)] internal interface IInternalNested { }
}
private protected class PrivateProtectedNestedClass
{
public interface IPublicNested { }
internal interface IInternalNested { }
}
private class PrivateNestedClass
{
public interface IPublicNested { }
internal interface IInternalNested { }
}
}
[TypeAccessibility(Accessibility.Internal)]
internal class RootInternalClass
{
[TypeAccessibility(Accessibility.Internal)]
public enum PublicEnumNested
{
}
[TypeAccessibility(Accessibility.Internal)]
internal enum InternalEnumNested
{
}
[TypeAccessibility(Accessibility.Internal)]
public class PublicNestedClass
{
[TypeAccessibility(Accessibility.Internal)] public interface IPublicNested { }
[TypeAccessibility(Accessibility.Internal)] internal interface IInternalNested { }
}
protected class ProtectedNestedClass
{
public interface IPublicNested { }
internal interface IInternalNested { }
}
[TypeAccessibility(Accessibility.Internal)]
protected internal class ProtectedInternalNestedClass
{
[TypeAccessibility(Accessibility.Internal)] public interface IPublicNested { }
[TypeAccessibility(Accessibility.Internal)] internal interface IInternalNested { }
}
[TypeAccessibility(Accessibility.Internal)]
internal class InternalNestedClass
{
[TypeAccessibility(Accessibility.Internal)] public interface IPublicNested { }
[TypeAccessibility(Accessibility.Internal)] internal interface IInternalNested { }
}
private protected class PrivateProtectedNestedClass
{
public interface IPublicNested { }
internal interface IInternalNested { }
}
private class PrivateNestedClass
{
public interface IPublicNested { }
internal interface IInternalNested { }
}
}
namespace My
{
[TypeAccessibility(Accessibility.Public)]
public enum PublicEnumNested
{
}
[TypeAccessibility(Accessibility.Internal)]
internal enum InternalEnumNested
{
}
[TypeAccessibility(Accessibility.Public)]
public class MyPublicClass
{
[TypeAccessibility(Accessibility.Public)]
public class PublicNestedClass
{
[TypeAccessibility(Accessibility.Public)] public interface IPublicNested { }
[TypeAccessibility(Accessibility.Internal)] internal interface IInternalNested { }
}
protected class ProtectedNestedClass
{
public interface IPublicNested { }
internal interface IInternalNested { }
}
[TypeAccessibility(Accessibility.Internal)]
protected internal class ProtectedInternalNestedClass
{
[TypeAccessibility(Accessibility.Internal)] public interface IPublicNested { }
[TypeAccessibility(Accessibility.Internal)] internal interface IInternalNested { }
}
[TypeAccessibility(Accessibility.Internal)]
internal class InternalNestedClass
{
[TypeAccessibility(Accessibility.Internal)] public interface IPublicNested { }
[TypeAccessibility(Accessibility.Internal)] internal interface IInternalNested { }
}
private protected class PrivateProtectedNestedClass
{
public interface IPublicNested { }
internal interface IInternalNested { }
}
private class PrivateNestedClass
{
public interface IPublicNested { }
internal interface IInternalNested { }
}
[TypeAccessibility(Accessibility.Public)] public enum PublicEnumNested { }
[TypeAccessibility(Accessibility.Internal)] internal enum InternalEnumNested { }
}
[TypeAccessibility(Accessibility.Internal)]
internal class MyInternalClass
{
[TypeAccessibility(Accessibility.Internal)]
public class PublicNestedClass
{
[TypeAccessibility(Accessibility.Internal)] public interface IPublicNested { }
[TypeAccessibility(Accessibility.Internal)] internal interface IInternalNested { }
}
protected class ProtectedNestedClass
{
public interface IPublicNested { }
internal interface IInternalNested { }
}
[TypeAccessibility(Accessibility.Internal)]
protected internal class ProtectedInternalNestedClass
{
[TypeAccessibility(Accessibility.Internal)] public interface IPublicNested { }
[TypeAccessibility(Accessibility.Internal)] internal interface IInternalNested { }
}
[TypeAccessibility(Accessibility.Internal)]
internal class InternalNestedClass
{
[TypeAccessibility(Accessibility.Internal)] public interface IPublicNested { }
[TypeAccessibility(Accessibility.Internal)] internal interface IInternalNested { }
}
private protected class PrivateProtectedNestedClass
{
public interface IPublicNested { }
internal interface IInternalNested { }
}
private class PrivateNestedClass
{
public interface IPublicNested { }
internal interface IInternalNested { }
}
[TypeAccessibility(Accessibility.Internal)] public enum PublicEnumNested { }
[TypeAccessibility(Accessibility.Internal)] internal enum InternalEnumNested { }
}
}
LINQPad 7
void Main()
{
var exportedTypes = typeof(TypeAccessibilityAttribute).Assembly.GetExportedTypes().ToHashSet();
typeof(TypeAccessibilityAttribute).Assembly
.GetTypes()
.Where(x => x.FullName.StartsWith("My") || x.FullName.StartsWith("Root"))
.Select(t =>
{
var info = t.GetTypeInfo();
return new
{
t.FullName,
Aacessibility = GetAccessibility(t)?.Accessibility.ToString() ?? "",
GetAacessibility = t.GetAccessibility(),
IsExported = exportedTypes.Contains(t),
t.IsVisible,
t.IsPublic,
t.IsNotPublic,
t.IsNested,
t.IsNestedPublic,
t.IsNestedFamily,
t.IsNestedPrivate,
t.IsNestedAssembly,
t.IsNestedFamORAssem,
t.IsNestedFamANDAssem,
t.Attributes,
};
})
.OrderBy(x => x.FullName)
.Dump();
}
TypeAccessibilityAttribute? GetAccessibility(Type type)
{
return type.GetCustomAttribute<TypeAccessibilityAttribute>();
}
検証結果
FullName | Aacessibility | GetAacessibility | IsExported | IsVisible | IsPublic | IsNotPublic | IsNested | IsNestedPublic | IsNestedFamily | IsNestedPrivate | IsNestedAssembly | IsNestedFamORAssem | IsNestedFamANDAssem |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
My.InternalEnumNested | Internal | Internal | True | ||||||||||
My.MyInternalClass | Internal | Internal | True | ||||||||||
My.MyInternalClass+InternalEnumNested | Internal | Internal | True | True | |||||||||
My.MyInternalClass+InternalNestedClass | Internal | Internal | True | True | |||||||||
My.MyInternalClass+InternalNestedClass+IInternalNested | Internal | Internal | True | True | |||||||||
My.MyInternalClass+InternalNestedClass+IPublicNested | Internal | Internal | True | True | |||||||||
My.MyInternalClass+PrivateNestedClass | None | True | True | ||||||||||
My.MyInternalClass+PrivateNestedClass+IInternalNested | None | True | True | ||||||||||
My.MyInternalClass+PrivateNestedClass+IPublicNested | None | True | True | ||||||||||
My.MyInternalClass+PrivateProtectedNestedClass | None | True | True | ||||||||||
My.MyInternalClass+PrivateProtectedNestedClass+IInternalNested | None | True | True | ||||||||||
My.MyInternalClass+PrivateProtectedNestedClass+IPublicNested | None | True | True | ||||||||||
My.MyInternalClass+ProtectedInternalNestedClass | Internal | Internal | True | True | |||||||||
My.MyInternalClass+ProtectedInternalNestedClass+IInternalNested | Internal | Internal | True | True | |||||||||
My.MyInternalClass+ProtectedInternalNestedClass+IPublicNested | Internal | Internal | True | True | |||||||||
My.MyInternalClass+ProtectedNestedClass | None | True | True | ||||||||||
My.MyInternalClass+ProtectedNestedClass+IInternalNested | None | True | True | ||||||||||
My.MyInternalClass+ProtectedNestedClass+IPublicNested | None | True | True | ||||||||||
My.MyInternalClass+PublicEnumNested | Internal | Internal | True | True | |||||||||
My.MyInternalClass+PublicNestedClass | Internal | Internal | True | True | |||||||||
My.MyInternalClass+PublicNestedClass+IInternalNested | Internal | Internal | True | True | |||||||||
My.MyInternalClass+PublicNestedClass+IPublicNested | Internal | Internal | True | True | |||||||||
My.MyPublicClass | Public | Public | True | True | True | ||||||||
My.MyPublicClass+InternalEnumNested | Internal | Internal | True | True | |||||||||
My.MyPublicClass+InternalNestedClass | Internal | Internal | True | True | |||||||||
My.MyPublicClass+InternalNestedClass+IInternalNested | Internal | Internal | True | True | |||||||||
My.MyPublicClass+InternalNestedClass+IPublicNested | Internal | Internal | True | True | |||||||||
My.MyPublicClass+PrivateNestedClass | None | True | True | ||||||||||
My.MyPublicClass+PrivateNestedClass+IInternalNested | None | True | True | ||||||||||
My.MyPublicClass+PrivateNestedClass+IPublicNested | None | True | True | ||||||||||
My.MyPublicClass+PrivateProtectedNestedClass | None | True | True | ||||||||||
My.MyPublicClass+PrivateProtectedNestedClass+IInternalNested | None | True | True | ||||||||||
My.MyPublicClass+PrivateProtectedNestedClass+IPublicNested | None | True | True | ||||||||||
My.MyPublicClass+ProtectedInternalNestedClass | Internal | Internal | True | True | |||||||||
My.MyPublicClass+ProtectedInternalNestedClass+IInternalNested | Internal | Internal | True | True | |||||||||
My.MyPublicClass+ProtectedInternalNestedClass+IPublicNested | Internal | Internal | True | True | |||||||||
My.MyPublicClass+ProtectedNestedClass | None | True | True | ||||||||||
My.MyPublicClass+ProtectedNestedClass+IInternalNested | None | True | True | ||||||||||
My.MyPublicClass+ProtectedNestedClass+IPublicNested | None | True | True | ||||||||||
My.MyPublicClass+PublicEnumNested | Public | Public | True | True | True | True | |||||||
My.MyPublicClass+PublicNestedClass | Public | Public | True | True | True | True | |||||||
My.MyPublicClass+PublicNestedClass+IInternalNested | Internal | Internal | True | True | |||||||||
My.MyPublicClass+PublicNestedClass+IPublicNested | Public | Public | True | True | True | True | |||||||
My.PublicEnumNested | Public | Public | True | True | True | ||||||||
RootInternalClass | Internal | Internal | True | ||||||||||
RootInternalClass+InternalEnumNested | Internal | Internal | True | True | |||||||||
RootInternalClass+InternalNestedClass | Internal | Internal | True | True | |||||||||
RootInternalClass+InternalNestedClass+IInternalNested | Internal | Internal | True | True | |||||||||
RootInternalClass+InternalNestedClass+IPublicNested | Internal | Internal | True | True | |||||||||
RootInternalClass+PrivateNestedClass | None | True | True | ||||||||||
RootInternalClass+PrivateNestedClass+IInternalNested | None | True | True | ||||||||||
RootInternalClass+PrivateNestedClass+IPublicNested | None | True | True | ||||||||||
RootInternalClass+PrivateProtectedNestedClass | None | True | True | ||||||||||
RootInternalClass+PrivateProtectedNestedClass+IInternalNested | None | True | True | ||||||||||
RootInternalClass+PrivateProtectedNestedClass+IPublicNested | None | True | True | ||||||||||
RootInternalClass+ProtectedInternalNestedClass | Internal | Internal | True | True | |||||||||
RootInternalClass+ProtectedInternalNestedClass+IInternalNested | Internal | Internal | True | True | |||||||||
RootInternalClass+ProtectedInternalNestedClass+IPublicNested | Internal | Internal | True | True | |||||||||
RootInternalClass+ProtectedNestedClass | None | True | True | ||||||||||
RootInternalClass+ProtectedNestedClass+IInternalNested | None | True | True | ||||||||||
RootInternalClass+ProtectedNestedClass+IPublicNested | None | True | True | ||||||||||
RootInternalClass+PublicEnumNested | Internal | Internal | True | True | |||||||||
RootInternalClass+PublicNestedClass | Internal | Internal | True | True | |||||||||
RootInternalClass+PublicNestedClass+IInternalNested | Internal | Internal | True | True | |||||||||
RootInternalClass+PublicNestedClass+IPublicNested | Internal | Internal | True | True | |||||||||
RootInternalEnum | Internal | Internal | True | ||||||||||
RootPublicClass | Public | Public | True | True | True | ||||||||
RootPublicClass+InternalEnumNested | Internal | Internal | True | True | |||||||||
RootPublicClass+InternalNestedClass | Internal | Internal | True | True | |||||||||
RootPublicClass+InternalNestedClass+IInternalNested | Internal | Internal | True | True | |||||||||
RootPublicClass+InternalNestedClass+IPublicNested | Internal | Internal | True | True | |||||||||
RootPublicClass+PrivateNestedClass | None | True | True | ||||||||||
RootPublicClass+PrivateNestedClass+IInternalNested | None | True | True | ||||||||||
RootPublicClass+PrivateNestedClass+IPublicNested | None | True | True | ||||||||||
RootPublicClass+PrivateProtectedNestedClass | None | True | True | ||||||||||
RootPublicClass+PrivateProtectedNestedClass+IInternalNested | None | True | True | ||||||||||
RootPublicClass+PrivateProtectedNestedClass+IPublicNested | None | True | True | ||||||||||
RootPublicClass+ProtectedInternalNestedClass | Internal | Internal | True | True | |||||||||
RootPublicClass+ProtectedInternalNestedClass+IInternalNested | Internal | Internal | True | True | |||||||||
RootPublicClass+ProtectedInternalNestedClass+IPublicNested | Internal | Internal | True | True | |||||||||
RootPublicClass+ProtectedNestedClass | None | True | True | ||||||||||
RootPublicClass+ProtectedNestedClass+IInternalNested | None | True | True | ||||||||||
RootPublicClass+ProtectedNestedClass+IPublicNested | None | True | True | ||||||||||
RootPublicClass+PublicEnumNested | Public | Public | True | True | True | True | |||||||
RootPublicClass+PublicNestedClass | Public | Public | True | True | True | True | |||||||
RootPublicClass+PublicNestedClass+IInternalNested | Internal | Internal | True | True | |||||||||
RootPublicClass+PublicNestedClass+IPublicNested | Public | Public | True | True | True | True | |||||||
RootPublicEnum | Public | Public | True | True | True |
感謝
関連記事
新着記事