如何创建一个“指针式”类,轻松暴露成员的功能?

时间:2015-02-02 07:18:08

标签: c#

我要做的是找到一种最优雅的方式来创建一个类似指针的"我在项目中具有的特定对象/类类的类。

我的意思是没有例子就有点混乱。拿这个非常简单的课程:

public class MyClass 
{
    private string _name;
    public string GetName() { return _name; }
    public void SetName(string name) { _name = name; }
}

我想创建一个第二个类,就像这样的指针:

public class MyClassPtr
{
    private MyClass _obj;
    public bool IsValid = false;

    public MyClassPtr(MyClass obj) { _obj = obj; IsValid = true; }

    public void InvalidatePtr()
    {
        IsValid = false;
        obj = null;
    }

    // SOME MAGIC HERE?
}

挑战:关键是我要优雅MyClassPtrMyClass 中的所有公共方法/成员提供一个界面,而不是围绕每个方法/成员编写包装器和/或访问器。

我知道我可以这样做:

public class MyClassPtr
{
    public string GetName() { return _obj.GetName(); }
    ...
}

但那是我想要避免的。 是否存在一些我不知道的基本抽象,我可以将其应用于MyClassPtr以允许它轻松地重新公开MyClass中通过_obj定向的方法/成员?我不希望MyClassPtr继承MyClassMyClassPtr应该是一个类型,还有一些技巧与访问者公开MyClass的方法/成员?


修改:有关我为什么要通过示例寻找此类设计的更多背景信息。这是总体目标。想象一个解析人员数据的平台,当它找到有关某人的信息时,它会创建一个包含该信息的Person实例。你可以得到一个像这样的人:

Person person1 = platform.GetPerson(based_on_data);

现在,想象一下这个平台有两个Person的实例,它认为是不同的人,但突然发现的信息强烈暗示这两个实例实际上是指同一个人。因此,平台希望将实例合并到一个新对象中,让我们将其称为personX

现在,在平台上漂浮的人有一个合并的两个实例之一的副本,即person1。我想要做的是使用person1即时替换personX。从字面上看,我希望person1==personX是真的,而不仅仅是它们是具有相同数据的两个不同对象。这很重要,因为平台可以对personX进行更改,除非两个对象在字面上相同,否则personX的更改不会自动反映在person1中。

由于我无法使用person1动态替换personX我有这样的想法,即我无法直接访问Person,而是我可以访问PersonPtr平台(即时)可以更改它所指向的Person。一旦person1ptr更新为指向personX,如果在personX中进行了更改,则会在person1ptr

中看到此保险

1 个答案:

答案 0 :(得分:1)

你当然可以使用像

这样的东西
public class MyClassWrapper
{
    MyClass _obj;
    public MyClassWrapper(MyClass obj)
    {
        _obj = obj; 
    }

    public void Invoke(Action<MyClass> action)
    {
        action(_obj);
    }

    public U Invoke<U>(Func<MyClass, U> func)
    {
        return func(_obj);
    }

    public void ChangeTo(MyClass obj)
    {
        _obj = obj;
    }
}

鉴于你的班级看起来像

public class MyClass 
{
    public string Name { get; set; }
}

示例:

var person1 = new MyClass { Name = "Instance1" };
var person2 = new MyClass { Name = "Instance2" };

var wrapper = new MyClassWrapper(person1);

wrapper.Invoke(x => x.Name += "original");
var x = wrapper.Invoke(x => x.Name); // Instance1original

wrapper.ChangeTo(person2);

var y = wrapper.Invoke(x => x.Name); // Instance2

但它有一个主要缺点:您无法直接访问成员,因此您无法绑定数据(DataTableControl)。

最好在你的包装类中实现你的类的所有成员。如果您担心类中的更改将被遗忘在包装器中实现,只需使用界面:

public interface IMyClass
{
    string Name { get; set; }
}
public class MyClass : IMyClass
{
    public string Name { get; set; }
}

public class MyClassWrapper: IMyClass
{
    MyClass _obj;
    public MyClassWrapper(MyClass obj)
    {
        _obj = obj; 
    }

    public string Name
    {
        get { return _obj.Name; }
        set { _obj.Name = value; }
    }
}

请注意,无论使用哪种方法,您都必须始终保持对包装器实例的引用以实际更改基础实例(使用类似static之类的内容)。

此外,更改此类包装器的基础实例而不告诉组件使用它更改它似乎不是一个好主意。也许你的系统很简单,可以使用包装器;这是你必须自己决定的事情。

也许你的包装器应该只有一个Invalid标志(和/或使用一个事件来表示底层对象的变化)。合并基础对象后,它将设置为true,并且每个成员访问都应该抛出异常。这将强制使用包装器的组件有意地对更改做出反应并从服务重新加载数据。

总而言之,我认为使用这样的包装器会使代码混乱并且容易出错(只需想象添加多线程就可以了)。如果你真的需要这个包装,请三思而后行。

为什么不在每次使用它时只是向您的服务询问您的类的新实例(该服务可以简单地使用缓存)?当然,你不能阻止某个地方有人参考;但至少你会保持理智。