代码之家  ›  专栏  ›  技术社区  ›  Anthony Waqas Raja

有没有办法在C中的对象初始值设定项块中使用扩展方法#

  •  6
  • Anthony Waqas Raja  · 技术社区  · 16 年前

    下面的简单演示捕获了我正在尝试做的事情。在实际的程序中,我必须使用对象初始化器块,因为它正在读取LINQ to SQL select表达式中的列表,并且有一个值我想从数据库中读取并存储在对象上,但是该对象没有一个简单的属性,我可以为该值设置。相反,它有一个XML数据存储。

    看起来我不能在对象初始化器块中调用扩展方法,也不能使用扩展方法附加属性。

    我有一个现有的解决方案,其中我将BaseDataObject子类化,但这也有一些问题,在这个简单的示例中没有显示出来。对象被持久化并恢复为BaseDataObject—强制转换和测试将变得复杂。

    public class BaseDataObject
    {
    
        // internal data store
        private Dictionary<string, object> attachedData = new Dictionary<string, object>();
    
        public void SetData(string key, object value)
        {
            attachedData[key] = value;
        }
    
        public object GetData(string key)
        {
            return attachedData[key];
        }
    
        public int SomeValue { get; set; }
        public int SomeOtherValue { get; set; }
    
    }
    
    public static class Extensions
    {
        public static void SetBarValue(this BaseDataObject dataObject,
                                            int            barValue)
        {
            /// Cannot attach a property to BaseDataObject?
            dataObject.SetData("bar", barValue);
        }
    }
    
    public class TestDemo
    {
    
        public void CreateTest()
        {
            // this works
            BaseDataObject test1 = new BaseDataObject 
            { SomeValue = 3, SomeOtherValue = 4 };
    
            // this does not work - it does not compile
            // cannot use extension method in the initialiser block
            // cannot make an exension property  
            BaseDataObject test2 = new BaseDataObject { SomeValue = 3, SomeOtherValue = 4, SetBarValue(5) };
        }
    }
    

    其中一个答案(来自mattlant)建议使用流畅的界面风格扩展方法。例如。:

    // fluent interface style
    public static BaseDataObject SetBarValueWithReturn(this BaseDataObject dataObject, int barValue)
    {
        dataObject.SetData("bar", barValue);
        return dataObject;
    }
    
    // this works
    BaseDataObject test3 = (new BaseDataObject { SomeValue = 3, SomeOtherValue = 4 }).SetBarValueWithReturn(5);
    

    6 回复  |  直到 6 年前
        1
  •  5
  •   Tigraine    16 年前

    var x = new BaseDataObject { SomeValue = 3, SomeOtherValue = 4 };
    

    将使编译器执行以下操作:

    BaseDataObject tempObject = new BaseDataObject();
    tempObject.SomeValue = 3;
    tempObject.SomeOtherValue = 4;
    BaseDataObject x = tempObject;
    

    区别在于不可能存在任何同步问题。变量x get一次分配了完全分配的BaseDataObject,在初始化过程中不能弄乱该对象。

    您可以在创建对象后调用扩展方法:

    var x = new BaseDataObject { SomeValue = 3, SomeOtherValue = 4 };
    x.SetBarValue()
    

    public int BarValue
    {
        set
        {
            //Value should be ignored
        }
    }
    

    或者,您可以子类化/使用facade模式将方法添加到对象中:

    public class DataObjectWithBarValue : BaseDataObject
    {
        public void BarValue
        {
            set
            {
                SetData("bar", value);
            }
            get
            {
                (int) GetData("bar");
            }
        }
    }
    
        2
  •  4
  •   mattlant    16 年前

    不,但你可以这样做

    BaseDataObject test2 = (new BaseDataObject { SomeValue = 3, SomeOtherValue = 4}).SetBarValue(5);
    

    让您的扩展像Linq一样返回对象。

    编辑:这是一个很好的想法,直到我重新阅读并看到基类是由第三方开发的:也就是说,你没有代码。这里的其他人发布了正确的解决方案。

        3
  •  3
  •   Pop Catalin    16 年前

    更好的是:

    public static T SetBarValue<T>(this T dataObject, int barValue)
            where T : BaseDataObject 
        {
            dataObject.SetData("bar", barValue);
            return dataObject;
        }
    

    并且,您可以对BaseDataObject的派生类型使用此扩展方法来链接没有强制转换的方法,并在推断到var字段或匿名类型时保留真实类型。

        4
  •  1
  •   Mark Cidade    16 年前
     static T WithBarValue<T>(this T dataObject, int barValue)
            where T : BaseDataObject 
     {  dataObject.SetData("bar", barValue);    
        return dataObject;
     }
    
    var x = new BaseDataObject{SomeValue=3, OtherValue=4}.WithBarValue(5);
    
        5
  •  0
  •   Guvante    16 年前

    扩大a类的可能性吗?然后,您可以轻松添加所需的属性。

    如果做不到这一点,您可以创建一个具有类似属性的新类,只需回调您感兴趣的类的私有实例即可。

        6
  •  0
  •   Anthony Waqas Raja    16 年前

    "

    我创建了一个子类,例如。

    public class SubClassedDataObject : BaseDataObject
    {
        public int Bar
        {
            get { return (int)GetData("bar"); }
            set { SetData("bar", value); }
        }
    }
    

    它在LINQ中运行良好,初始化块看起来像

        SubClassedDataObject testSub = new SubClassedDataObject
        { SomeValue = 3, SomeOtherValue = 4, Bar = 5 };
    

    在代码的其余部分中,我忽略了子类并使用了扩展方法:

        public static void SetBar(this BaseDataObject dataObject, int barValue)
        {
            dataObject.SetData("bar", barValue);
        }
        public static int GetBar(this BaseDataObject dataObject)
        {
            return (int)dataObject.GetData("bar");
        }