我正在编写与第三方应用程序互操作的应用程序.此应用程序通过DLL中的方法向开发人员公开API.前一段时间,这个应用程序的供应商开始将他们自己的.NET组件集成到他们的程序中,当他们这样做时,他们决定他们的组件应该ConfigurationManager在运行时使用它来获取设置.
这意味着什么:他们的程序,foo.exe调用fooengine.dll,以及从中读取其设置foo.exe.config.我的程序,bar.exe也调用fooengine.dll,它从中读取其设置bar.exe.config.
嗯,这是完全错误的.但是我该如何解决呢?
简单的解决方法是复制foo.exe.config的设置bar.exe.config.那会奏效,但这很愚蠢.这意味着从管理角度来看,必须在N个不同的文件中维护给定的设置.这迟早会失败.
我尝试在配置文件中configSource的appSettings部分放置一个属性.(碰巧,我正在使用该applicationSettings部分进行我的设置,他们正在使用他们的appSettings部分,所以我可以忍受只是从不同的文件中获取该部分.)但是ConfigurationManager不喜欢它:它想要路径configSource不仅相对于我的程序目录而且在我的程序目录之下.
我可以将他们的设置文件读取到一个XmlDocument然后自己设置.但是现在我将我的代码与他们的实现紧密结合起来; 如果他们推出了一个将设置移动到该applicationSettings部分的新版本(现在应该是2009年的版本),我的代码将会中断.
还有另一种出路吗?
我正在测试我构建的用户控件,我遇到的东西对我来说是莫名其妙的.
该控件是ComboBox的扩展,用于处理特定自定义类型的值.它具有该自定义类型的依赖项属性,该属性是Binding的目标属性.
我在setter中有一个trace语句,我可以看到该属性已经设置好了.但它没有出现在我的用户控件中.
现在,通常我会说,好吧,我的用户控件中有一个错误.我可能会这样做,虽然我对此感到困惑.但这个问题不是要找到我控制中的错误.继续阅读; 这里是奇怪的地方.
我也使用Bea Stollnitz的小值转换器来帮助调试绑定:
public class DebuggingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value; // Add the breakpoint here!!
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException("This method should never be called");
}
}
Run Code Online (Sandbox Code Playgroud)
这背后的想法是我将这个转换器添加到我的Binding中,并且可以设置一个断点来查看推送到目标的值.好的,这很好用.我可以看到价值被推出.
事实上,它的工作有点太精细了.如果DebuggingConverter附加到Binding,则用户控件将显示该值.如果不是,那就没有.
这怎么可能呢?如果一个值转换器不会影响绑定控件的行为?
编辑:
并不是说它可能有所帮助,但这是用户控件的XAML:
<a:CodeLookupBox
Grid.Column="1"
Grid.IsSharedSizeScope="True"
MinWidth="100"
Style="{Binding Style}">
<a:CodeLookupBox.CodeLookupTable>
<Binding Path="Codes" Mode="OneWay"/>
</a:CodeLookupBox.CodeLookupTable>
<a:CodeLookupBox.SelectedCode>
<Binding Path="Value" Mode="TwoWay" ValidatesOnDataErrors="True"/>
</a:CodeLookupBox.SelectedCode>
</a:CodeLookupBox>
Run Code Online (Sandbox Code Playgroud)
如果没有第二个绑定上的转换器,控件就像我没有设置一样SelectedCode …
我无法在任何地方找到答案,在我开始使用Reflector生成代码之前我认为值得问:
假设我在DataSet中对DataTables运行以下LINQ查询:
var list =
from pr in parentTable.AsEnumerable()
join cr in childTable.AsEnumerable() on cr.Field<int>("ParentID") equals pr.Field<int>("ID")
where pr.Field<string>("Value") == "foo"
select cr;
Run Code Online (Sandbox Code Playgroud)
如果父表与使用显示的关键字段的子表之间存在DataRelation,LINQ会使用它吗?也就是说,它会在父表中找到Value为"foo"的行,然后调用GetChildRows项目子行吗?
或者这是我必须明确指定的内容吗?(如果是这样,我该怎么做?)
这是我班级的简化版本:
public abstract class Task
{
private static object LockObject = new object();
protected virtual void UpdateSharedData() { }
protected virtual void UpdateNonSharedData() { }
public void Method()
{
lock(LockObject)
{
UpdateSharedData();
}
UpdateNonSharedData();
}
}
Run Code Online (Sandbox Code Playgroud)
我试图隐藏派生类的锁定代码.但是如果派生类重写UpdateSharedData,我只想获取锁; 如果没有,我不希望该方法阻止并等待在更新共享数据之前更新共享数据的所有其他正在运行的实例.
所以对于Method来说(看似)显而易见的事情是检查并查看当前实例的UpdateSharedData实现是否覆盖了基类的实现.我很确定如果不使用反射这是不可能的,并且可能不希望这样做.
我已经想到了一些解决方法,但它们都很尴尬:
我遇到了令人困惑的XML反序列化问题.
我正在构建一个支持本地自定义其使用的各种服务的应用程序.我已经实现了一个抽象ServiceLocator类,其方法返回各种对象.每个自定义安装都负责实现此类的子类并提供这些方法的实现.这个类的肉看起来像这样:
public abstract class ServiceLocator
{
public static void Initialize(string customFeaturesPath)
{
Assembly a = Assembly.LoadFrom(customFeaturesPath);
Type t = a.GetExportedTypes()
.AsEnumerable()
.Where(x => x.IsSubclassOf(typeof (ServiceLocator)))
.First();
Default = (ServiceLocator)a.CreateInstance(t.FullName);
}
public static ServiceLocator Default { get; private set; }
public abstract DefaultValuesContainer CreateDefaultValuesContainer();
}
Run Code Online (Sandbox Code Playgroud)
这很好用:我从应用程序配置文件中获取自定义功能程序集的路径,程序调用Initialize,然后应用程序可以调用各种方法,ServiceLocator.Default并返回相应的服务自定义实现.
其中一项服务是DefaultValuesContainer.这是一个简单的对象,它公开了需要在用户设置文件中保存其值的属性.我的想法是我可以将此对象序列化为单个用户设置类型string.它使得用户设置文件不想手动编辑,但我很酷.
这是一个具体的实现ServiceLocator.CreateDefaultValuesContainer:
protected override DefaultValuesContainer CreateDefaultValuesContainer(string serializedXml)
{
DefaultValuesContainer c = new ClientDefaultValuesContainer();
if (string.IsNullOrEmpty(serializedXml))
{
return c;
}
XmlSerializer x = …Run Code Online (Sandbox Code Playgroud) 我有麻烦了。我正在开发的应用程序的用户之一偶尔但有规律地遇到应用程序挂起的情况。
发生这种情况时,我们会在计算机的事件日志中找到一个带有“应用程序挂起”源的条目,并提供提示性消息“挂起应用程序[我的应用程序],版本[正确的版本],挂起模块hungapp,版本0.0.0.0,挂起地址0x00000000。”
我正在记录应用程序引发的所有未处理的异常,并且在发生这种情况时,日志文件中没有任何条目。
我目前的工作假设是,在应用程序调用不安全的旧版API时会发生这种挂起。这不会令我惊讶。我已经使用此API多年了,虽然我之前从未见过它挂起过,但它确实是糟糕的代码。此外,用户报告该程序似乎在随机时间挂起。我认为这不是真的。不是我不相信她,而是与旧版API对话的代码在由BackgroundWorker调用的方法中运行。如果后台线程使应用程序挂起,那么用户可能会觉得它像随机发生的那样。
因此,我有两个问题,一个是具体问题,一个是一般问题。
具体问题是:我希望如果在非UI线程上运行的方法挂起,它将杀死该线程。实际上会杀死整个应用程序吗?
一般问题:
我已经在记录所有未处理的异常。我的程序已经设置为使用跟踪(尽管我将需要添加工具代码来跟踪可疑方法中的活动)。还有其他我应该做的事情吗?.NET应用程序挂起时,是否有诊断工具可以进行某种崩溃后分析?我可以调用.NET框架内的机制来捕获更多(和更多可用的)数据吗?
编辑: 在仔细检查我的代码时,我记得它对BackgroundWorker的所有使用都是通过我实现的实用程序类实现的,该实用程序类包装了在异常处理程序中调用的方法。该处理程序记录该异常,然后将其作为实用程序对象的所有权返回。UI线程中的完成事件处理程序重新引发了异常(不理想,因为我丢失了调用堆栈,但已经记录了该异常),导致UI的主要异常处理程序将异常报告给消息框,然后终止该异常。应用程式。
由于这一切都没有发生,因此我非常有信心在后台线程中不会引发任何异常。好吧,无论如何,.NET没有例外。
进一步跟进:
幸运的是,我现在已经从用户那里获得了足够的数据,以确保不会在旧版API中发生死机。这显然是我做错的事情,这意味着我可以解决问题,所以赢了。这也意味着我可以通过跟踪来隔离问题,这是另一个胜利。我对这个问题的答案感到非常高兴;我更高兴我可能不需要这个问题。
另外:PostSharp非常出色。如果需要在现有应用程序中添加检测代码,则几乎可以肯定应该使用它。
如果我使用的是Hashtable,我可以编写如下代码:
object item = hashtable[key] ?? default_value;
Run Code Online (Sandbox Code Playgroud)
无论是否key出现在Hashtable.
我不能这样做Dictionary<TKey. TValue>.如果密钥不在字典中,那将抛出一个KeyNotFoundException.所以我必须编写如下代码:
MyClass item;
if (!(dict.TryGetValue(key, out item))
{
item = default_value;
}
Run Code Online (Sandbox Code Playgroud)
我想知道为什么会这样. Dictionary<TKey, TValue>只是一个包装Hashtable.为什么要添加此限制?
编辑:
关于PopCatalin的答案的另一个观点(见下文),如果字典的值是值类型,我上面写的代码将不起作用.如果我使用Dictionary<int, int>,然后将代码,我会喜欢用看起来像这样:
int i = dict[key] ?? default_value;
Run Code Online (Sandbox Code Playgroud)
而且这不会编译,因为dict[key]它不是可空或引用类型.
这很普遍-尤其是当您尝试使代码变得更加数据驱动时-需要遍历关联的集合。例如,我刚刚完成了一段代码,如下所示:
string[] entTypes = {"DOC", "CON", "BAL"};
string[] dateFields = {"DocDate", "ConUserDate", "BalDate"};
Debug.Assert(entTypes.Length == dateFields.Length);
for (int i=0; i<entTypes.Length; i++)
{
string entType = entTypes[i];
string dateField = dateFields[i];
// do stuff with the associated entType and dateField
}
Run Code Online (Sandbox Code Playgroud)
在Python中,我将编写类似以下内容的内容:
items = [("DOC", "DocDate"), ("CON", "ConUserDate"), ("BAL", "BalDate")]
for (entType, dateField) in items:
# do stuff with the associated entType and dateField
Run Code Online (Sandbox Code Playgroud)
我不需要声明并行数组,不需要断言我的数组长度相同,也不需要使用索引来取出项目。
我感觉有一种使用LINQ在C#中执行此操作的方法,但我不知道它可能是什么。是否有一些简单的方法可以遍历多个关联的集合?
编辑:
我认为,这要好一些-至少在我可以在声明时手动压缩集合并且所有集合都包含相同类型的对象的情况下:
List<string[]> items = new List<string[]>
{
new [] {"DOC", "DocDate"},
new [] {"CON", …Run Code Online (Sandbox Code Playgroud) 我正在使用networkx包.networkx中是否有可以为我完成任务的功能?
我正在与想要为遗留应用程序添加功能的客户合作.供应商无用的应用程序具有Windows窗体UI.我的客户想要的是当用户点击应用程序中的一条信息时触发此应用程序之外的某些功能.
我已经看到了另一个客户的简单版本.在这种情况下,有一个应用程序,包含一个已设置为最顶层窗口的表单SetWindowPos.当用户单击此表单上的按钮时,应用程序会找到旧版应用程序的窗口,并从窗口的标题中获取信息.这是不优雅的 - 即使传统的应用程序没有打开,这个浮动按钮永远不会消失 - 但它的工作原理.
我想知道是否可以使用带有Topmost属性集的无边框透明WPF窗口执行类似的操作.我正在考虑的应用程序将分析遗留应用程序窗口中的内容并定义热点列表.它将截取并处理热点中的任何鼠标点击,并将所有剩余的鼠标点击传递到旧版应用程序.
我对Windows API并不十分熟悉,所以我不知道实现这种功能是否简单(甚至可能).在我看来,如果我正在编写反恶意软件工具,我想到的应用程序正是我试图削弱的那种东西.
如果这实际上是一个可行的项目,那么最好的方法是什么?我应该注意哪些意想不到的问题?
c# ×6
.net ×3
linq ×2
wpf ×2
binding ×1
datarelation ×1
dataset ×1
diagnostics ×1
dictionary ×1
hang ×1
hashtable ×1
inheritance ×1
iteration ×1
join ×1
networkx ×1
overriding ×1
production ×1
python ×1
reflection ×1
topmost ×1
winapi ×1
winforms ×1