繁体   English   中英

获取类中声明的变量名

[英]Get the declared variable name in a class

我想做这样的事情 - 在那里我捕获对象内部的原始声明对象变量名称。

 public class Foo
    {
        private string _originalDeclarer;
        
        public Foo(string originalDeclarer=nameof(this))
        {
            _originalDeclarer = originalDeclarer;
        }

        public string OriginalDeclarer
        {
            get => _originalDeclarer;
            set => _originalDeclarer = value;
        }
    }

    public static class Bar
    {
        public static void CreateFoos()
        {
            Foo GreenFoo = new Foo();
            Foo BlueFoo = new Foo();
            
            Console.WriteLine(GreenFoo);
            Console.WriteLine(BlueFoo);
            
            //Expected output
            // "GreenFoo"
            // "BlueFoo"
        }    
    }

以上可以理解是行不通的,我知道变量名没有存储在运行时元数据中,所以这个问题的一般答案是它无法完成。

也就是说,研究使我找到了几种解决方法,我正在寻找最好的方法。

这个问题很好地完成了提案:

class Self
{
    public string Name { get; }

    public Self([CallerMemberName] string name = null)
    {
        this.Name = name;
    }
}

然后:

class Foo
{
    private Self me = new Self(); // Equivalent to new Self("me")

    public void SomeMethod()
    {
        // Can't use the default here, as it would be "SomeMethod".
        // But we can use nameof...
        var joe = new Self(nameof(joe));
    }
}

我还没有测试以上是否有效,但缺点对我来说是有问题的。

我有 - 但我很难找到我在这个问题中找到的较早答案,其中名称在编译时被替换。

如果有人有解决这个问题的方法(即使它慢得可怕)或者知道编译时替换的方式,我会非常感兴趣。

如果我可以在方法中停止实例化,上述建议的解决方法对我有用。

编辑上下文这里是我使用普通枚举的示例 - 我宁愿用我自己的强类型类型替换枚举:ConfiguredDatabase 是一个枚举。

private Result<DatabaseConnectionStatus> TestDatabase(ConfiguredDatabase database)
        {
            SqlDataAccessLayer sqlDataAccessLayer = DetailsStore.DataAccessLayers.TryGetbyUId(database.ToString());

            if (sqlDataAccessLayer.ConnectionDetails.DataSource == string.Empty)
            {
                return Result.Failed($"Database connection is not configured for {database}", DatabaseConnectionStatus.NoConnectionConfigured);
            }
        }

查看您的最后一次添加,我不建议使用枚举类型来确定您的数据库。 如果您的枚举类型在稍后阶段删除了值,则会出现问题,例如

enum ConfiguredDatabase
{
  Database1,
  // Database2, 
  Database3
}

现在 Database3 的值与过去 Database2 的值相同。 如果您为每个分配固定值,那么仍然可以在您的调用代码中使用分配给 Database2 的值!

相反,我建议通过将接口传递给具体的类类型来坚持一些依赖注入原则。

例如,沿着这些路线的东西。

public interface IConfiguredDatabase
{
  string ConnectionString;
}

public Database1 : IConfiguredDatabase
{
  public Database1
  {
    ConnectionString = "Database One";
  }
  public string ConnectionString{get;set;}
}

public Database2 : IConfiguredDatabase
{
  public Database1
  {
    ConnectionString = "Database Two";
  }
  public string ConnectionString{get;set;}
}

private Result<DatabaseConnectionStatus> TestDatabase(IConfiguredDatabase database)
        {
            SqlDataAccessLayer sqlDataAccessLayer = DetailsStore.DataAccessLayers.TryGetbyUId(database.ConnectionString);

            if (sqlDataAccessLayer.ConnectionDetails.DataSource == string.Empty)
            {
                return Result.Failed($"Database connection is not configured for {database.ConnectionString}", DatabaseConnectionStatus.NoConnectionConfigured);
            }
        }

然后在其他地方你称之为:

using (var d = new Database1()
{
  var result = TestDatabase(d);

...
}

我知道我的示例并不完全适合您的代码,但我希望它能让您了解我的建议。

如果您确实需要使用反射来确定您的调用属性是什么,那么我建议您采用以下模式。 我在 MVVM 中将它用于 ViewModel 类,因此使用 OnPropertyChanging 和 OnPropertyChanging 事件,但我相信您会明白这个想法。

您可以调整 BaseClass.SetProperty 以调用其他代码或引发事件以满足您的需要。

public class BaseClass
{
    /// <summary>
    ///     Worker function used to set local fields and trigger an OnPropertyChanged event
    /// </summary>
    /// <typeparam name="T">Parameter class</typeparam>
    /// <param name="backingStore">Backing field referred to</param>
    /// <param name="value">New value</param>
    /// <param name="propertyName">Property that this value is applied to </param>
    /// <param name="onChanged">Event handler to invoke on value change</param>
    /// <param name="onChanging">Event handler to invoke on value changing</param>
    /// <returns></returns>
    protected bool SetProperty<T>(
        ref T backingStore, T value,
        [CallerMemberName] string propertyName = "",
        Action onChanged = null,
        Action<T> onChanging = null)
    {
        if (EqualityComparer<T>.Default.Equals(backingStore, value)) return false;

        onChanging?.Invoke(value);
        OnPropertyChanging(propertyName);

        backingStore = value;
        onChanged?.Invoke();
        OnPropertyChanged(propertyName);
        return true;
    }

    /// <summary>
    ///     INotifyPropertyChanging event handler
    /// </summary>
    public event PropertyChangingEventHandler PropertyChanging;

    /// <summary>
    ///     INotifyOnPropertyChanging implementation
    /// </summary>
    /// <param name="propertyName">Class property that is changing</param>
    protected void OnPropertyChanging([CallerMemberName] string propertyName = "")
    {
        var changing = PropertyChanging;

        changing?.Invoke(this, new PropertyChangingEventArgs(propertyName));
    }

    /// <summary>
    ///     INotifyPropertyChanged event handler
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    ///     INotifyPropertyChanged implementation
    /// </summary>
    /// <param name="propertyName">Class property that has changed</param>
    protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        var changed = PropertyChanged;

        changed?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

}

public class SomeClass : BaseClass
{
    private int _propertyOne;
    private string _propertyTwo;
    
    public int PropertyOne
    {
        get=> return _propertyOne;
        set=> SetProperty(ref _propertyOne, value);
    }
    
    public int PropertyTwo
    {
        get=> return _propertyOne;
        set=> SetProperty(ref _propertyTwo, value);
    }   
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM