有好文章提出了不同的实施方式INotifyPropertyChanged.
考虑以下基本实现:
class BasicClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void FirePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
private int sampleIntField;
public int SampleIntProperty
{
get { return sampleIntField; }
set
{
if (value != sampleIntField)
{
sampleIntField = value;
FirePropertyChanged("SampleIntProperty"); // ouch ! magic string here
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我想用这个替换它:
using System.Runtime.CompilerServices;
class BetterClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
// Check the attribute …Run Code Online (Sandbox Code Playgroud) 我试图CallerMemberName通过BCL可移植包在.NET 4.0中使用属性.它总是返回一个空字符串而不是成员名称.我究竟做错了什么?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
MessageBox.Show(new class2().CallMe);
}
}
public class class2
{
public string CallMe
{
get
{
return HelpMe();
}
}
private string HelpMe([CallerMemberName] string param = "")
{
return param;
}
}
Run Code Online (Sandbox Code Playgroud) 随着.NET 4.5.3的出现,WPF开发人员现在有三种(或更多)方法来通知INotifyPropertyChanged接口属性更改.基本上,我的问题是从.NET 4.5开始引入的两种方法中哪一种是更有效的方式来通知属性更改以及在WPF中使用时这两种方式是否有任何好处?
背景
对于那些不太熟悉这个主题的人,这里有三个主要方法.第一个是简单传递字符串的原始的,更容易出错的方法:
public string TestValue
{
get { return testValue; }
set { testValue = value; NotifyPropertyChanged("TestValue"); }
}
protected virtual void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Run Code Online (Sandbox Code Playgroud)
第二种方法是在.NET 4.5中引入的; 的CallerMemberNameAttribute:
public string TestValue
{
get { return testValue; }
set { testValue = value; NotifyPropertyChanged(); }
}
protected virtual void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); …Run Code Online (Sandbox Code Playgroud) 我有以下代码:
ViewPortViewModel _Trochoid;
public ViewPortViewModel Trochoid
{
get { return _Trochoid; }
set { this.RaiseAndSetIfChanged(value); }
}
Run Code Online (Sandbox Code Playgroud)
使用ReactiveUI INPC支持.编译器始终警告我Trochoid永远不会分配给它,并且始终为null.然而,由于RaiseAndSetIfChanged通过CallerMemberName支持执行的魔术,代码确实有效并且编译器是错误的.
如何在我的代码中干净地压制这些警告?
c# inotifypropertychanged suppress-warnings reactiveui callermembername
与此问题类似,我想将可选参数与params关键字混合,这当然会产生歧义.不幸的是,创建重载的答案不起作用,因为我想利用调用者信息属性,如下所示:
public void Info(string message, [CallerMemberName] string memberName = "",
[CallerLineNumber] int lineNumber = 0, params object[] args)
{
_log.Info(BuildMessage(message, memberName, lineNumber), args);
}
Run Code Online (Sandbox Code Playgroud)
在没有可选参数的情况下创建重载会更改调用站点,从而阻止这些特定参数正常工作.
我找到了一个几乎可以工作的解决方案(虽然很难看):
public void Info(string message, object arg0, [CallerMemberName] string memberName = "",
[CallerLineNumber] int lineNumber = 0)
{
_log.Info(BuildMessage(message, memberName, lineNumber), arg0);
}
public void Info(string message, object arg0, object arg1, [CallerMemberName] string memberName = "",
[CallerLineNumber] int lineNumber = 0)
{
_log.Info(BuildMessage(message, memberName, lineNumber), arg0, arg1);
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是,如果为最后一个参数指定一个字符串,则重载决策假定您打算memberName在重载中显式指定需要较少的参数,这不是所需的行为.
有没有办法实现这一点(也许使用一些我没有学过的新属性?)或者我们是否只是达到了自动魔法编译器支持可以给我们的极限?
我刚刚看到了C#5来电者信息属性(http://msdn.microsoft.com/en-us/library/hh534540.aspx).
这似乎是一个非常有用的功能,我已经阅读了一些文档(http://www.codeproject.com/Tips/606379/Caller-Info-Attributes-in-Csharp).
但是,我只是想知道:为什么必须传递默认值?它们是如何使用的?
以下示例代码显示了如何使用调用者信息属性:
public static void ShowCallerInfo([CallerMemberName]
string callerName = null, [CallerFilePath] string
callerFilePath = null, [CallerLineNumber] int callerLine=-1)
{
Console.WriteLine("Caller Name: {0}", callerName);
Console.WriteLine("Caller FilePath: {0}", callerFilePath);
Console.WriteLine("Caller Line number: {0}", callerLine);
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:什么是默认值null,null以及-1用来做什么?上面的代码如何不同于:
public static void ShowCallerInfo([CallerMemberName]
string callerName = "hello", [CallerFilePath] string
callerFilePath = "world", [CallerLineNumber] int callerLine=-42)
{
Console.WriteLine("Caller Name: {0}", callerName);
Console.WriteLine("Caller FilePath: {0}", callerFilePath);
Console.WriteLine("Caller Line number: {0}", callerLine);
}
Run Code Online (Sandbox Code Playgroud)
我理解它的方式,这些是可选参数,编译器提供默认值,替换我们分配的默认值.在这种情况下,我们为什么要指定默认值?是否有一些奇怪的边缘情况,编译器可能无法填写值,并转向我们提供的默认值?如果没有,那么为什么要求我们输入这些数据呢?要求开发者提供永远不会使用的默认值似乎相当笨拙.
免责声明:我试过谷歌搜索,但我找不到任何东西.我几乎害怕在SO上提问,因为大多数这样的新手问题都会遇到这样的敌意,但作为最后的手段,我会冒一个问题.主持人/高级用户,没有违法行为 - …
我正在尝试将C#5.0来电者信息与C#params关键字结合起来.目的是为日志框架创建一个包装器,我们希望记录器像String.Format一样格式化文本.在以前的版本中,方法如下所示:
void Log(
string message,
params object[] messageArgs = null);
Run Code Online (Sandbox Code Playgroud)
我们称之为:
log.Log("{0}: I canna do it cap'n, the engines can't handle warp {1}!",
"Scotty", warpFactor);
Run Code Online (Sandbox Code Playgroud)
现在,我们想要捕获调用者信息并记录它们.签名变为:
void Log(
string message,
params object[] messageArgs,
[CallerMemberName] string sourceMemberName = null);
Run Code Online (Sandbox Code Playgroud)
这不会编译,因为参数必须是最后一个参数.所以我试试这个:
void Log(
string message,
[CallerMemberName] string sourceMemberName = null,
params object[] messageArgs);
Run Code Online (Sandbox Code Playgroud)
有没有办法在没有提供sourceMembername的情况下调用它,或者将messageArgs参数显式指定为命名参数?这样做会破坏params关键字的用途:
// params is defeated:
log.Log("message",
messageArgs: new object[] { "Scotty", warpFactor });
// CallerMemberName is defeated:
log.Log("message", null,
"Scotty", warpFactor);
Run Code Online (Sandbox Code Playgroud)
有没有办法做到这一点?似乎传递调用者信息的"hacky"方式排除了使用params关键字.如果C#编译器认识到调用者成员信息参数根本不是真正的参数,那将是很棒的.我认为没有必要明确地传递它们.
我的备份将跳过params关键字,并且调用者必须在最后一个示例中使用长签名.
我已经INotifyPropertyChanged实现了CallerMemberName
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Run Code Online (Sandbox Code Playgroud)
因此,可以在任何属性的设置器中将OnPropertyChanged()其称为- ,它会在设置属性时通知属性更改事件。仅属性获取器不是这种情况。例如,
private DateTime _dob;
public DateTime DateOfBirth
{
get
{
return _dob;
}
private set
{
_dob = value;
OnPropertyChanged();
OnPropertyChanged("Age");
}
}
public int Age
{
get
{
return DateTime.Today.Year - _dob.Year;
}
}
Run Code Online (Sandbox Code Playgroud)
OnPropertyChanged()对于DateOfBirth可以正常使用,但是要通知Age更改,我应该记得OnPropertyChanged("Age")在的setter中进行调用DateOfBirth。我觉得这使得代码很难随时间进行维护。如果新属性取决于年龄,则还需要在DateOfBirth的设置器中进行通知。有没有更好的方法可以执行此操作而无需调用OnPropertyChanged(“ Age”)?
如果我将这些属性应用于某些服务,然后将其注入到 DI 中,我正在尝试弄清楚将使用哪个CallerMemberName或CallerFilePath值。例如:
public class MyService: IMyService
{
public MyService([CallerMemberName] string name = null)
{
var name = name; // name is always null here
}
}
...
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyService, MyService>();
}
}
Run Code Online (Sandbox Code Playgroud)
所以,我想,这是name变量的预期值还是我做错了什么?CallerMemberName在这种情况下我该如何工作?有可能吗?
c# dependency-injection callermembername asp.net-core asp.net5
如何获得class-name与caller info attributes.
我strongly say a no用反射记录类名.
能够使用[CallerMemberName]下面的方法获取方法名称:
private void Log(string logMessage, [CallerMemberName]string callerName = null)
{
if (logger.IsDebugEnabled)
{
logger.DebugFormat("Executing Method = {1};{0}", logMessage, callerName);
}
}
Run Code Online (Sandbox Code Playgroud)
如何class name使用来电者信息属性登录?
c# ×10
callermembername ×10
.net ×3
.net-4.0 ×1
.net-4.6 ×1
asp.net ×1
asp.net-core ×1
asp.net5 ×1
c#-5.0 ×1
c#-6.0 ×1
nameof ×1
params ×1
reactiveui ×1
reflection ×1
wpf ×1