简体   繁体   English

如何在C#中创建访问object属性的接口?

[英]How to create an interface for accessing object properties in C#?

I want to generalize limited access to certain fields of an object:我想概括对 object 的某些字段的有限访问:

class Foo {
    public int Bar;
    public int Qux;
}

To do that, I've declared an interface:为此,我声明了一个接口:

interface IModifiableFoo {
    int Bar {get; set;}
}

Then to limit access to that object, I've made a class that wraps it:然后为了限制对该 object 的访问,我制作了一个 class 来包装它:

class ModifiableFoo : IModifiableFoo {
    private readonly Foo ActualFoo;

    ModifiableFoo(ref Foo foo) {
        ActualFoo = foo;
    }

    public int Bar {
        get => ActualFoo.Bar;
        set { ActualFoo.Bar = value; }
    }
}

Finally, I'm using this wrapper to offer limited access to the Foo object:最后,我使用这个包装器来提供对Foo object 的有限访问:

Foo myFoo = new Foo();

IModifiableFoo ModifyFoo() {
    return (IModifiableFoo) new ModifiableFoo(ref MyFoo);
}

IModifiableFoo fooAccess = ModifyFoo();
fooAccess.Bar = 3;

Console.WriteLine(myFoo.Bar); // 3

As a result, the contract IModifiableFoo acts as a generalization over what fields you can change when you gain the right to modify the Foo .因此,合同IModifiableFoo充当了当您获得修改Foo的权利时可以更改哪些字段的概括。

However, as the interface only declares a getter and a setter their actual implementation is not restricted, and allows this to happen:然而,由于接口只声明了一个 getter 和一个 setter,它们的实际实现不受限制,并允许这种情况发生:

class ModifiableFoo : IModifiableFoo {
    ModifiableFoo(ref Foo foo) {}

    public int Bar {
        get => 42,
        set {
            Console.WriteLine("Not something you would expect");
        }
    }
}

How do I implement this functionality and ensure that the implementation will always get and set the corresponding field?我如何实现这个功能并确保实现总是获取和设置相应的字段?

If you're looking to guarantee some portion of the implementation, then it seems to me the best way to control that would be to implement it.如果您希望保证实现的某些部分,那么在我看来,控制它的最佳方法就是实现它。 You know you want to expose a method, you know that it needs to wrap a Foo, and you know you want that method to cause things to happen to Foo in a consistent way, so perhaps an abstract class?您知道要公开一个方法,您知道它需要包装一个 Foo,并且您知道您希望该方法以一致的方式使 Foo 发生事情,所以也许是抽象的 class?

    public abstract class ModifiableFoo : IModifiableFoo
    {
        private Foo _foo;

        protected ModifiableFoo(Foo foo)
        {
            _foo = foo;
        }

        public int Bar
        {
            get => _foo.Bar; 
            set { _foo.Bar = value; }
        }
    }

    public class ExtendedModifiableFoo : ModifiableFoo
    {
        public ExtendedModifiableFoo(Foo foo) : base(foo)
        {

        }

        public int Bar // this doesn't work as shown because Bar is not overridable
        {
            get => _foo.Bar; // nor does this because _foo is inaccessible due to its protection level
        }
    }

A solution's shape fits a specific problem.解决方案的形状适合特定的问题。 From what I understand of your question, you want to control data read/write permissions at application runtime.根据我对您问题的了解,您希望在应用程序运行时控制数据读/写权限。 A CvarRegistry comes to mind.一个 CvarRegistry 浮现在脑海中。 Please refer to the original by id Software, as this is just an outline.请参考id Software的原文,这只是一个大纲。

    public Cvar { }
    public Cvar<T>
    {
        public T Value { get; set; }
    }
    public CvarRegistry : Dictionary<string, Cvar> { }

You could dynamically control access by: 1) adding and removing Cvars to the accessible collection, (hoping the consumers don't hold onto references) 2) adding getter-only versions to the accessible collection, or 3) building a regulator which exclusively toggles the readonly state of each Cvar value, which forces branching at setter access-time.您可以通过以下方式动态控制访问:1)向可访问集合添加和删除 Cvar,(希望消费者不要保留引用)2)向可访问集合添加仅 getter 版本,或 3)构建一个专门切换的调节器每个 Cvar 值的只读 state,这会在设置器访问时强制分支。

Unfortunately, an object property can be a whole object with its own accessible properties, and so artificial control leaks.不幸的是,一个 object 属性可以是一个完整的 object 具有自己的可访问属性,因此人为控制泄漏。 The real CvarRegistry is flat, as every Cvar points to a primitive.真正的 CvarRegistry 是平坦的,因为每个 Cvar 都指向一个原语。 I have not found a way to constrain generics to primitives, but I do not believe it necessary.我还没有找到将 generics 限制为原语的方法,但我认为没有必要。

OOP teaches you to conceptualize data as an object's personal property or state. OOP 教您将数据概念化为对象的个人财产或 state。 Realize this assumption forces you to then MANUALLY deliver the "state" values between "objects."意识到这个假设会迫使您在“对象”之间手动传递“状态”值。 This results in a form of process known as distributed manufacturing .这导致了一种称为分布式制造的过程形式。 Each OOP module has a redundant (internal) representation of the (shared) memory locations they control and e-mail to one another.每个 OOP 模块都有一个冗余(内部)表示(共享)memory 位置,它们控制并通过电子邮件相互发送。 In contrast, reference properties (Cvars) allow different modules to simply share memory.相比之下,引用属性 (Cvars) 允许不同的模块简单地共享 memory。

    public Cvar<int> x { get; set; }

    public void M()
    {
        x.Value += 3;
    }
    public void N() 
    {
        x.Value *= 4;
    }

    // N() could be a method in another class, another namespace
    // and you would have zero coupling

My manufacturing architecture is a whole alternative paradigm to OOP where modules interact with an end product, rather than artificially owning and controlling memory as if it's always internal state.我的制造架构是 OOP 的完全替代范例,其中模块与最终产品交互,而不是人为地拥有和控制 memory,就好像它始终是内部 state。 So another way to look at the problem is to ask whether "object properties" are necessary.所以另一种看待问题的方法是询问“对象属性”是否必要。 Sometimes they are, but not in a production context, which is most code.有时它们是,但不是在生产环境中,这是大多数代码。

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

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