有什么办法在C#中的对象初始化块中使用扩展方法吗?
下面的简单演示捕捉了我正在尝试做的事情。在真正的程序中,我必须使用对象初始化块,因为它正在读取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查询?
更妙的是:
public static T SetBarValue<T>(this T dataObject, int barValue)
where T : BaseDataObject
{
dataObject.SetData("bar", barValue);
return dataObject;
}
,你可以使用派生类型BaseDataObject与链方法,这种扩展方法没有强制转换,当推断为VAR字段或匿名类型保存真正的类型。
对象初始化器只需要一个聪明的编译器的语法糖,并且就目前的实现而言,您不能在初始化器中调用方法。
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");
}
}
}
不,但你可以这样做....:
BaseDataObject test2 = (new BaseDataObject { SomeValue = 3, SomeOtherValue = 4}).SetBarValue(5);
有你的扩展返回对象,如Linq Does。
编辑:这是一个好主意,直到我重读,并看到基类是由第三人开发的:又名你没有代码。其他人已经发布了正确的解决方案。
必须有很高的代表点才能去掉并删除错误的答案,而不是承认自己的错误:/(你知道你是谁是;)) – mattlant 2008-09-25 09:22: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);
权,已经从应答者了解到,短回答“是否有任何方法在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");
}
而且它工作得很好。
目的是将Set方法从BaseDataObject中抽象出来吗? 我强烈建议简单地使用获取/设置属性的子类化。 – Tigraine 2008-09-25 09:51:30