- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图在尝试访问之前检查一个属性是否存在于第 3 方 dll 中(为了向后兼容),为什么 if
语句返回 true 然后失败并出现异常 Method未找到:“Boolean Shared.Models.Account.get_EnsureTextField()”
当我访问该属性时?
var type = am.account.GetType(); //account is of type class Account
//See if Account does not have property EnsureTextField
if(type.GetProperty("EnsureTextField") != null)
{
cbEnsureTextField.Checked = am.account.EnsureTextField; //Exception thrown
}
注意:代码编译正常,因为确实使用了 EnsureTextField
的编译时版本,问题是代码在运行时失败(当加载同一程序集的不同版本时),即使根据我的理解,我有 if
检查应该防止异常。
最佳答案
从根本上说,尝试运行针对后来以向后不兼容的方式更改的库构建的代码是一个坏主意。虽然您可以如下所示解决它,但如果在各种地方看到怪癖,我不会感到惊讶,并且解决方法可能会变得越来越难以管理。如果有可能,最好退后一步并尝试更改您的依赖项管理流程以完全避免这种情况。
话虽如此,我明白了失败的原因:JIT 编译器无法对您的方法进行 JIT 编译,因为它找不到使用的方法引用 (get_EnsureText
)方法内。它甚至在评估 if
条件之前就失败了。
这里有一个小例子来证明这一点。从 Library.cs
开始:
public class Account
{
public string Name { get; set; }
}
将其编译为 Library.dll
。
然后编写Program.cs:
using System;
class Program
{
static void Main(string[] args)
{
var account = new Account();
if (DateTime.Now.Hour == 1000)
{
Console.WriteLine(account.Name);
}
}
}
请注意我们如何永远进入if
语句的主体,因为它永远不会是 1000 点钟。
编译它,引用Library.dll
。
接下来,注释掉Library.cs
中的Account.Name
,重新编译Library.dll
,然后重新运行Program.exe
:
Unhandled Exception: System.MissingMethodException: Method not found: 'System.String Account.get_Name()'.
at Program.Main(String[] args)
如果 JIT 编译器不会实际执行它,我们可以通过阻止 JIT 编译器尝试访问该属性来解决这个问题:
using System;
class Program
{
static void Main(string[] args)
{
var account = new Account();
if (DateTime.Now.Hour == 1000)
{
PrintAccountName(account);
}
}
static void PrintAccountName(Account account)
{
Console.WriteLine(account.Name);
}
}
跳完和之前一样的舞,这段代码现在可以毫无异常地执行。
现在没有使用反射...但我们可以很容易地改变它来这样做。更改 Library.cs
以默认为帐户命名:
public class Account
{
public string Name { get; set; } = "Default name";
}
然后更改 Program.cs
以仅在属性存在时使用该属性 - 但如果我们检查了它,甚至只调用直接引用该属性的方法:
using System;
class Program
{
static void Main(string[] args)
{
var account = new Account();
if (account.GetType().GetProperty("Name") != null)
{
PrintAccountName(account);
}
else
{
Console.WriteLine("Account.Name is missing");
}
}
static void PrintAccountName(Account account)
{
Console.WriteLine($"Account name: {account.Name}");
}
}
经历与之前相同的舞蹈,但每次都运行代码,我们最初得到的输出是:
Account name: Default name
但是删除属性并重新编译后,输出变为:
Account.Name is missing
...这就是您想要的。
这仅 有效,因为 JIT 编译器是逐个方法编译的。我不知道它会这样做的任何保证,而不是推测性地编译一个类型中的所有方法,如果其中任何一个有问题就会失败。所以这是一个非常脆弱的解决方案,但它至少对您来说是一个临时的解决方法。
替代方法
如问题评论中所述,您可以使用动态类型来避免将属性引用直接嵌入到 IL 中。下面是上述代码的一个略短的替代方案:
using System;
class Program
{
static void Main(string[] args)
{
var account = new Account();
if (account.GetType().GetProperty("Name") != null)
{
// Avoid a compile-time reference to the property
dynamic d = account;
Console.WriteLine($"Account name: {d.Name}");
}
else
{
Console.WriteLine("Account.Name is missing");
}
}
}
就不依赖 JIT 编译器实现细节而言,这肯定更简洁,而且可能更可靠。另一方面,它更容易出现拼写错误等,因为 d.Name
表达式在编译时根本 没有被检查。 (事实上 ,即使针对新版本的库,Program.cs
代码仍然可以编译。)
旁注
此代码仅测试是否有 属性。它可能是一个最初的读/写属性,但后来变成只写的,在这种情况下,我们仍然会尝试调用 get 访问器,但会失败。不过,可以修改您正在检查的条件以合理轻松地处理此问题。
关于c# - 当外部库不向后兼容时检查属性是否存在,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49959862/
你能比较一下属性吗 我想禁用文本框“txtName”。有两种方式 使用javascript,txtName.disabled = true 使用 ASP.NET, 哪种方法更好,为什么? 最佳答案 我
Count 属性 返回一个集合或 Dictionary 对象包含的项目数。只读。 object.Count object 可以是“应用于”列表中列出的任何集合或对
CompareMode 属性 设置并返回在 Dictionary 对象中比较字符串关键字的比较模式。 object.CompareMode[ = compare] 参数
Column 属性 只读属性,返回 TextStream 文件中当前字符位置的列号。 object.Column object 通常是 TextStream 对象的名称。
AvailableSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。 object.AvailableSpace object 应为 Drive 
Attributes 属性 设置或返回文件或文件夹的属性。可读写或只读(与属性有关)。 object.Attributes [= newattributes] 参数 object
AtEndOfStream 属性 如果文件指针位于 TextStream 文件末,则返回 True;否则如果不为只读则返回 False。 object.A
AtEndOfLine 属性 TextStream 文件中,如果文件指针指向行末标记,就返回 True;否则如果不是只读则返回 False。 object.AtEn
RootFolder 属性 返回一个 Folder 对象,表示指定驱动器的根文件夹。只读。 object.RootFolder object 应为 Dr
Path 属性 返回指定文件、文件夹或驱动器的路径。 object.Path object 应为 File、Folder 或 Drive 对象的名称。 说明 对于驱动器,路径不包含根目录。
ParentFolder 属性 返回指定文件或文件夹的父文件夹。只读。 object.ParentFolder object 应为 File 或 Folder 对象的名称。 说明 以下代码
Name 属性 设置或返回指定的文件或文件夹的名称。可读写。 object.Name [= newname] 参数 object 必选项。应为 File 或&
Line 属性 只读属性,返回 TextStream 文件中的当前行号。 object.Line object 通常是 TextStream 对象的名称。 说明 文件刚
Key 属性 在 Dictionary 对象中设置 key。 object.Key(key) = newkey 参数 object 必选项。通常是 Dictionary 
Item 属性 设置或返回 Dictionary 对象中指定的 key 对应的 item,或返回集合中基于指定的 key 的&
IsRootFolder 属性 如果指定的文件夹是根文件夹,返回 True;否则返回 False。 object.IsRootFolder object 应为&n
IsReady 属性 如果指定的驱动器就绪,返回 True;否则返回 False。 object.IsReady object 应为 Drive&nbs
FreeSpace 属性 返回指定的驱动器或网络共享对于用户的可用空间大小。只读。 object.FreeSpace object 应为 Drive 对象的名称。
FileSystem 属性 返回指定的驱动器使用的文件系统的类型。 object.FileSystem object 应为 Drive 对象的名称。 说明 可
Files 属性 返回由指定文件夹中所有 File 对象(包括隐藏文件和系统文件)组成的 Files 集合。 object.Files object&n
我是一名优秀的程序员,十分优秀!