是否可以在没有设置器的情况下在属性中设置值?
Posted
技术标签:
【中文标题】是否可以在没有设置器的情况下在属性中设置值?【英文标题】:Is is possible to set value in property without a setter? 【发布时间】:2019-06-16 16:01:31 【问题描述】:我正在使用这个包 (https://github.com/shawnmclean/Mandrill-dotnet) 在 .net 应用程序中实现 mandrill 现在有一个模型“EmailMessage”用于发送电子邮件。 EmailMessage 模型内部有一个属性“GlobalMergeVars”:
[JsonProperty("global_merge_vars")]
public List<MergeVar> GlobalMergeVars get;
现在我们可以看到 GlobalMergeVars 没有设置器,但我必须为此设置一个值。如果我们转到此链接 (https://mandrillapp.com/api/docs/messages.html) 并单击“试用”按钮,那么我们可以为 GlobalMergeVars 设置值,但我认为我正在使用的包中存在一些问题。但我不能切换到其他包,因为它与其他包相比非常灵活。那么无论如何要为 GlobalMergeVars 设置值吗?
PS:我还在 github repo 上打开了一个问题。但由于截止日期临近,我需要快速修复。
【问题讨论】:
从类的构造函数中试过了吗? EmailMessage 类中只有一个空的构造函数 请添加更多详细代码!还要告诉你要在哪种情况下设置值。 答案是:从第 376 行开始阅读github.com/shawnmclean/Mandrill-dotnet/blob/master/src/Mandrill/…。该方法专为您的情况设计 谢谢,这正是我想要的。 【参考方案1】:我想我找到了你所说的课程here。尽管EmailMessage
的属性与您在问题中显示的不同:
public class EmailMessage
#region Public Properties
...
/// <summary>
/// Gets the global_merge_vars.
/// </summary>
public List<MergeVar> GlobalMergeVars get; private set;
(此处的代码与问题中给出的代码之间的差异无关紧要 - 我只是想知道我是否正在查看正确的文件!)
缺少的set
相当于private set
。该类中有以下方法,可让您设置变量:
public void AddGlobalVariable(string name, dynamic content)
if (GlobalMergeVars == null)
GlobalMergeVars = new List<MergeVar>();
var mv = new MergeVar Name = name, Content = content;
GlobalMergeVars.Add(mv);
【讨论】:
【参考方案2】:我知道您已经得到了针对您的特定情况的答案,但是由于问题是“是否可以在没有 setter 的情况下在属性中设置值?”并且明确地说您不能直接从类外设置值,我只是想提供一个这样做的例子......
如果您愿意使用反射,您实际上可以从类外部设置值。
你只需要有点棘手。
您需要滥用这样一个事实,即为 Auto 属性生成的私有字段是由编译器脱糖而不是由 JITer 生成的。
这意味着程序集中实际上会有一个这样命名的私有字段:k__BackingField.
编译器去糖添加 因为它们被开发人员代码添加为私有字段名称是非法的。
这是一个示例,我试图查找名为 GlobalIgnores 的属性的私有支持字段,该属性没有设置器(与拥有私有设置器的含义相同)。
public class Configuration
public Configuration()
GlobalIgnores = new List<string>"IgnoredPropertyName";
public IEnumerable<string> GlobalIgnores get;
protected IList<string> PropertyNamesToTempIgnore get; = new List<string>"ReplacedIgnoredPropertyName";
public void SetPrivateBackingFieldOfPropertyWithNoSetter()
var configuration = new Configuration();
var configurationType = configuration.GetType();
const string globalIgnoresFieldName = "<GlobalIgnores>k__BackingField";
var fieldInfo = configurationType.GetField(globalIgnoresFieldName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
fieldInfo.SetValue(configuration, PropertyNamesToTempIgnore);
免责声明:除非绝对必要,否则我不建议使用它,因为这些自动生成的私有字段的命名不是 100% 在 C# 规范中指定的,并且它可能会在不同的编译器实现中发生变化。
【讨论】:
【参考方案3】:很抱歉成为坏消息的承担者,但如果没有公共设置器,您无法直接从类外设置值。其他选项将通过构造函数或允许这样的方法。但您似乎没有任何可用的此类选项。
附带说明一下,只需检查该属性是否可能没有您可以作为一个整体设置的父属性。例如在 C# 中使用字体时,例如设置标签的字体。某些 Font 对象的属性是“只读的”,不能在外部设置。但是可以设置 Font 对象本身。因此,在这种情况下,您必须在本地创建一个新的 Font 对象并设置所需的道具,然后将其分配/设置为新的 Font。
希望您能及时找到解决办法。
更新:
Rufo 爵士刚刚给了你解决方案:
答案是:阅读时间 github.com/shawnmclean/Mandrill-dotnet/blob/master/src/Mandrill/… 从第 376 行开始。该方法专为您的情况设计
【讨论】:
你忘了说可能有一种方法可以完成这项工作(事实上,有一个);o) @SirRufo - 不,我确实提到过,只是添加了您的解决方案。赞一个!以上是关于是否可以在没有设置器的情况下在属性中设置值?的主要内容,如果未能解决你的问题,请参考以下文章
iOS 在组件中存储随机属性,例如没有子类的 UITextField