66. What is reflection?
反射是一种机制,它使我们能够编写可以检查应用程序中所 用类型的代码。例如,调用名称与给定字符串相等的方法,或者列出属于给定 对象的所有字段及其值。
在 Convert 方法中,我们根本不知道处理的是什么类型。我们无法将 "obj"强制转换为任何具体的类型,因为类型可能会有所不同。而且,要实现我们 想要的功能,我们不仅需要属性的值(如果我们有比 System.Object 更具体的类型, 就可以访问这些值),还需要属性的名称,但在运行时这是无法获取的。
What are the downsides of using reflection? 使用反射会对性能产生相对较大的影响。此外,它会使代码难以理解和 维护。它还可能诱使一些程序员在运行时"破解"某些代码,例如访问私有 字段,这可能会导致意外的结果和难以理解的错误
68. What is serialization?
序列化是将对象转换为可存储在内存中或通过网络传输的格式的过程。例 如,对象可以被转换为包含 JSON 或 XML 的文本文件,或者转换为二进制 文件。
What are the uses of serialization? 它可用于通过网络发送对象,或者将对象存储在文件中以便日后重建,甚至 可以将对象存储在数据库中------例如,每当用户对某个对象进行更改时,都 保存该对象的一个"快照",这样我们就能记录更改的历史记录
Serializable 属性的作 用是什么?
cs
[Serializable]
public record Person
此属性表明类的实例可以使用 BinaryFormatter 或 SoapFormatter 进行序列化。对 于 XML 或 JSON 序列化则无需此属性。BinaryFormatter 将对象序列化为二进制 格式(简单来说,就是一串 0 和 1),而 SoapFormatter 则序列化为 SOAP 格式, 这种格式与 XML 有些类似。
What does the Serializable attribute do? 此属性表明类的实例可以使用 BinaryFormatter 或 SoapFormatter 进行序列化。对于 XML 或 JSON 序列化,此属性并非必需
What is deserialization? 反序列化是序列化的相反过程:它是利用文件的内容重新创建 对象
69. What is pattern matching?
How can we check if an object is of a given type, and cast to it this type in the same statement? 我们可以使用模式匹配来实现这一点。例如,我们可以这样写:"如果 obj 是字符串 text"。这样,只有当 obj 是字符串类型时,我们才会将其转换为名 为 text 的字符串变量
79. What is caching?
如果该值尚未缓存,我们需要以某种方式获取它。 对于 PeopleController 来说,它会从存储库中读取。但我们不能这样做: 缓存类是泛型的,它不仅必须适用于从特定存储库读取的人员对象,还必 须适用于其他任何对象。换句话说,我们还必须提供一种通用机制来读取 将要存储在缓存中的值。最简单的解决方案是将一个 Func 传递给 Get 方法。 此 Func 将返回一个类型为 TValue 的对象。由 Get 方法的调用方提供具体 的读取方法。在我们的例子中,PeopleController将使用缓存,并向 Get 方 法传递一个从数据库读取 Person 对象的函数
cs
using Microsoft.Extensions.Caching.Memory;
var peopleController = new PeopleController(
new PeopleRepositoryMock());
var john = peopleController.GetByName("John", "Smith");
john = peopleController.GetByName("John", "Smith");
john = peopleController.GetByName("John", "Smith");
Console.ReadKey();
//还添加了非空约束。字典的键绝不能为 null。
class Cache<TKey, TValue> where TKey: notnull
{
private readonly Dictionary<TKey, TValue> _cachedData = new();
//首先,它应该将一个键作为参数:
public TValue Get(TKey key, Func<TValue> getValueForTheFirstTime)
{
if (!_cachedData.ContainsKey(key))
{
_cachedData[key] = getValueForTheFirstTime();
}
//如果字典中已存储给定键对应的值,则应直接返回该值:
return _cachedData[key];
}
}
class PeopleController
{
//我们希望可以通过提供名字和姓氏来检索它们。所以也许最好的选择是一个字典,
//其中由两个字符串组成的元组(分别代表名字和姓氏)作为键,Person 对象作为值。
private readonly Cache<(string, string), Person?> _cache = new();
private readonly IRepository<Person> _peopleRepository;
public PeopleController(IRepository<Person> peopleRepository)
{
_peopleRepository = peopleRepository;
}
public Person? GetByName(string firstName, string lastName)
{
//Get 方法的第一个参数是键,在我们的例子中是一个包含名和姓的 ValueTuple。
//第二个参数是一个函数,用于从存储库中检索具有这些姓名的 Person 对象。
return _cache.Get(
(firstName, lastName),
() => _peopleRepository
.GetByName(firstName, lastName)
.FirstOrDefault());
}
private readonly MemoryCache _memoryCache =
new MemoryCache(new MemoryCacheOptions());
//alternatively we can use the Microsoft's MemotyCache
public Person? GetByNameMemoryCache(string firstName, string lastName)
{
return _memoryCache.GetOrCreate(
(firstName, lastName),
cacheEntry => _peopleRepository
.GetByName(firstName, lastName)
.FirstOrDefault());
}
}
internal interface IRepository<T>
{
IEnumerable<Person> GetByName(string firstName, string lastName);
}
record Person(string FirstName, string LastName);
class PeopleRepositoryMock : IRepository<Person>
{
public IEnumerable<Person> GetByName(string firstName, string lastName)
{
if (firstName == "John" && lastName == "Smith")
{
return new[] { new Person("John", "Smith") };
}
throw new NotImplementedException();
}
}
What are the benefits of using caching? 如果反复通过相同的键检索数据,缓存可以提升性能。它不仅有助于从外部 数据源检索数据,甚至对于本地计算的数据也有帮助,尤其是当计算本身比 较繁重(例如某些复杂的数学运算)时
What are the downsides of using caching? 缓存会占用应用程序的内存。随着时间的推移,缓存可能会不断增大,因此 应当引入某种清理机制以避免出现内存溢出异常。这类机制通常基于数据的 过期时间。此外,缓存中的数据可能会过时,即在数据源中已发生变化,但缓存 中仍保留旧版本并在应用程序中使用。正因为如此,缓存对于那些不常变化 的数据最为有用