【问题标题】:How do I determine if a property is a user-defined type in C#?如何确定属性是否是 C# 中的用户定义类型?
【发布时间】:2014-05-21 21:09:51
【问题描述】:

如何确定属性是否为用户定义类型?我尝试使用 IsClass,如下所示,但它的值对于 String 属性是正确的(谁知道还有什么)。

foreach (var property in type.GetProperties()) {
    if (property.PropertyType.IsClass) {
        // do something with property
    }
}

* 更新更清晰 *

我正在尝试遍历给定类型的定义,如果在程序集中定义了给定类型或其任何公共属性,我正在搜索嵌入的 JavaScript 文档。我只是不想在原生 .NET 类型上浪费处理资源和时间。

【问题讨论】:

  • 很明显,因为string 是一个类。您如何区分“用户定义”类型和另一个?来自外部非标准库的类型是“用户定义的”吗?
  • 你知道类对象吗?这样的事情怎么样? "if (property.PropertyType == typeof(MyClass)) { ... }" 或者您可以在您的情况下使用它来忽略字符串。
  • 如果您能详细说明为什么需要它或这样做的目的是什么,也许会有所帮助。
  • Bill - 我认为你真的应该告诉我们为什么你想这样做 - 可能有更好的方法。

标签: c# reflection


【解决方案1】:

@Bobson 提出了一个非常好的观点:

"...与其他一些语言不同,C# 没有任何实际的 “用户定义”和“标准”类型之间的区别。”

从技术上讲,@Bobson 给出了答案;用户定义的类型与在 .NET Framework 或任何其他程序集中定义的类型之间没有区别。

但是,我发现了几种有用的方法来确定类型是否是用户定义的。

要搜索给定类型的程序集中定义的所有类型,这非常有用:

foreach (var property in type.GetProperties()) {
    if (property.PropertyType.IsClass 
    && property.PropertyType.Assembly.FullName == type.Assembly.FullName) {
        // do something with property
    }
}

如果可以在各种程序集中定义类型,则排除 System 命名空间在大多数情况下有效:

foreach (var property in type.GetProperties()) {
    if (property.PropertyType.IsClass 
    && !property.PropertyType.FullName.StartsWith("System.")) {
        // do something with property
    }
}

【讨论】:

  • 我还会添加“Microsoft”。排除列表的命名空间
  • 当您使用property.PropertyType.Assembly == type.Assembly 时也可以使用。 FullName 属性是必需的。
【解决方案2】:

如果“用户定义”是指它不是标准程序集 (mscorlib) 的一部分,那么您可以按照以下方式进行操作:

if(typeof(SomeType).Assembly.GetName().Name != "mscorlib") {
    // user-defined!
}

但是,这也会将来自外部程序集(又名:库)的类型视为“用户定义”。如果您只想要当前程序集中的那些,那么您可以使用

typeof(SomeType).Assembly == Assembly.GetExecutingAssembly()

【讨论】:

  • 这不是很灵活的解决方案。请参阅下面的my answer。您可以使用我的代码示例来确定在当前正在执行的程序集中或在您指定的任何程序集中声明的类型。
  • 我也添加了类似的区别。但是有很多边缘情况:一些程序集是用户定义的,但与执行的程序集不同,因此它们将被错误地排除在外。根据它的严格程度,最好将黑名单列入太少而不是太多。
  • 确实如此。您始终可以从您在项目中引用的任何外部程序集获取类型列表。
  • 这将排除核心 .NET 程序集,但不排除 ASP.NET、MVC、实体框架等的所有其他基础结构程序集。
  • @BillHeitstuman:我相信您要么必须检查它是否在执行程序集中,要么提供程序集的黑名单/白名单并检查它是否在适当的列表中。
【解决方案3】:

我为单元测试编写了一个通用填充器,它为我的对象分配了可预测的值,但遇到了这种问题。就我而言,我想知道我的哪些属性是对象,以便我可以递归地填充这些对象属性,再次使用可预测的值。

在我看来,引入一个只由我感兴趣的类实现的接口是最好的方法。然后,您可以测试您的财产是否是感兴趣的对象:

    public static bool IsMyInterface(this Type propertyType)
    {
        return propertyType.GetInterface("MyInterfaceName") != null;
    }

【讨论】:

    【解决方案4】:

    假设您的项目名为“Foobar”,并且您所做的一切都在该命名空间下。可以通过下面的方法测试一下是否写过:

    typeof(SomeType).Namespace.Contains("Foobar");
    

    【讨论】:

      【解决方案5】:

      在更新数据库时创建日志时,我也遇到了这个问题。我不希望这些类显示在日志中,因为它们从不 == 在数据和 dto 之间。

      foreach (PropertyType item in properties)
      {
          if((item.PropertyType.IsClass && item.PropertyType.FullName.StartsWith("System.")) || !item.PropertyType.IsClass)
          {
             //...do stuff
          }
      }
      

      这让我可以处理标记为类的字符串等。

      【讨论】:

        【解决方案6】:

        如果“用户定义”类型是指在执行程序集中声明的类型,那么您可以获得该类型的列表,如以下示例 c# 控制台应用程序:

        class Program
        {
            static void Main( string[] args )
            {
                var currentAssembly = Assembly.GetExecutingAssembly();
                var localTypes = currentAssembly.GetTypes();
            }
        }
        

        更新:

        如果你想从所有引用的程序集中获取类型列表:

        class Program
        {
            static void Main( string[] args )
            {
                var currentAssembly = Assembly.GetExecutingAssembly();
                var referencedAssemblies = currentAssembly.GetReferencedAssemblies();
                var typesFromReferencedAssemblies = referencedAssemblies.Select( assemblyName => Assembly.ReflectionOnlyLoad( assemblyName.FullName ) ).SelectMany( assembly => assembly.GetTypes() );
            }
        }
        

        请注意Program 类型也将在该列表中。这足以解决您的问题吗?

        【讨论】:

        • 这个答案也有问题:例如,类库是一个不同的程序集,但它不是“执行”的程序集......
        • @rsenna 您还可以从您想要的任何程序集中获取类型列表。 var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();var referencedAssemblies = someAssembly.GetReferencedAssemblies(); 然后在它们上调用 GetTypes() 方法。
        • 抱歉,我相信最后的编辑让一切变得更糟——现在你得到了 all 引用类型,无论是否“用户定义”。我想你的第一个答案至少对于一些简单的情况来说已经足够好了。我也相信没有简单的方法可以让你的代码变得更好。除此之外,我不知道,解析解决方案文件并找出所有“用户定义的项目”(即使这不适用于所有情况)。
        • @rsenna 我添加了有关如何从引用的程序集中获取类型的示例,因为您建议“例如,类库是一个不同的程序集,但不是“执行”程序集。此外我的回答是,问题是:为什么有人需要检查 SomeType 是否是用户定义的。也许他应该重构他的代码,这样他就不需要检查了。
        • 抱歉,我没有“建议”任何事情——我只是说您的解决方案存在局限性。许多有效的答案都有限制,这本身并没有错。但我相信您的答案在更新后变得最差(获取引用程序集的列表将获得所有程序集,“用户定义”与否)。
        猜你喜欢
        • 1970-01-01
        • 2011-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-01
        • 2011-02-08
        • 1970-01-01
        相关资源
        最近更新 更多