2008-09-25 20 views
6

下面的简单演示捕捉了我正在尝试做的事情。在真正的程序中,我必须使用对象初始化块,因为它正在读取LINQ到SQl选择表达式中的列表,并且存在一个值,我想读取数据库并将其存储在对象上,但对象没有一个简单的属性,我可以为该值设置。相反,它有一个XML数据存储。有什么办法在C#中的对象初始化块中使用扩展方法吗?

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

所以,我运气不好,这种做法?唯一的选择似乎是说服基类的所有者对这种情况进行修改。

我有一个现有的解决方案,我的子类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); 

但是,这将工作在LINQ查询?

+0

目的是将Set方法从BaseDataObject中抽象出来吗? 我强烈建议简单地使用获取/设置属性的子类化。 – Tigraine 2008-09-25 09:51:30

回答

3

更妙的是:

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

,你可以使用派生类型BaseDataObject与链方法,这种扩展方法没有强制转换,当推断为VAR字段或匿名类型保存真正的类型。

4

对象初始化器只需要一个聪明的编译器的语法糖,并且就目前的实现而言,您不能在初始化器中调用方法。

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() 

你可以改变SetBarValue,使之与在初始化时被分配的get/set属性:

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

或者,您可以继承/使用立面图案将该方法添加到您的物体上:

public class DataObjectWithBarValue : BaseDataObject 
{ 
    public void BarValue 
    { 
     set 
     { 
      SetData("bar", value); 
     } 
     get 
     { 
      (int) GetData("bar"); 
     } 
    } 
} 
4

不,但你可以这样做....:

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

有你的扩展返回对象,如Linq Does。

编辑:这是一个好主意,直​​到我重读,并看到基类是由第三人开发的:又名你没有代码。其他人已经发布了正确的解决方案。

+0

必须有很高的代表点才能去掉并删除错误的答案,而不是承认自己的错误:/(你知道你是谁是;)) – mattlant 2008-09-25 09:22:16

0

正在扩大班级的可能性吗?然后你可以轻松地添加你需要的属性。

如果做不到这一点,你可以创建具有相似特性,简单地再打给你感兴趣的类的私有实例的新类。

1
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); 
0

权,已经从应答者了解到,短回答“是否有任何方法在C#中的对象初始化程序块中使用扩展方法?”是“

,我终于得到了解决,我所面临的问题(类似,但更复杂的是,我在这里提出的问题玩具)是一种混合的方法,如下的方式:

我创建了一个子类,例如

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 }; 

但是,我不喜欢在首位这种做法的原因是,这些对象被放入XML而来作为BaseDataObject退出,并且退回将是一个烦恼,一个不必要的数据副本,并且会放置同一对象的两个副本。

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

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"); 
    } 

而且它工作得很好。

相关问题