如何在Delphi中动态构造泛型类型?
让我解释
如果我有一个界面IMyInterface<T>
,
我想动态分配泛型T
参数并以某种方式获取对该类型的引用.
function GetInterfaced(aType : PTypeInfo) : TRttiType
begin
Result := ???
// I want to return TypeInfo(IMyInterface<aType>);
// or a RttiType that corresponds to TRttiContext.GetType(IMyInterface<aType>)
end;
Run Code Online (Sandbox Code Playgroud)
如何动态构建此泛型类型?
一个限制,我不能使用
function GetInterfaced<T> : TRttiType
begin
Result := TrttiContext.Create.GetType(TypeInfo(IMyInterface<T>))
end;
Run Code Online (Sandbox Code Playgroud)
编辑
我正在尝试使用Stefan的Spring4d容器创建一个类型来解析组件
例如 :
function ResolveLookup(aModelType : PTypeInfo) : TObject
var aLookupType : PTypeInfo
begin
aLookupType := SomehowGetTypeOf(ILookup<aModelType>);
Result := FContainer.Resolve(aLookupType).AsObject;
end;
Run Code Online (Sandbox Code Playgroud)
我真正的用例是我定义了一组模型(
TAssociate = class(TModel)
TUser = class(TModel)
TMandate = class(TModel)
Run Code Online (Sandbox Code Playgroud)
我还为他们定义了"查找"视图:
TAssociateLookup = …
Run Code Online (Sandbox Code Playgroud) 我正在努力用DUnit成功模拟一个Spring4d事件.
事实上,我更嘲笑一个模拟返回模拟事件...
这是基本结构.
TMyObject --EventContainer--> TMock<IEventContainer> --Event--> TMock<IEvent>
Run Code Online (Sandbox Code Playgroud)
TMyObject有一个属性EventContainer:IEventContainer
IEventContainer有一个属性Event:IMyEvent
我想嘲笑
MyObject.EventContainer.Event.Add
Run Code Online (Sandbox Code Playgroud)
我测试了我能想到的每种可能性.我得到AV或无效的演员.我把源代码放在下面.如果有人能帮助我让这个工作真的很漂亮!
program Project2;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
DUnitTestRunner,
Spring.Events,
Spring,
Classes,
TestFramework,
Delphi.Mocks;
//Unit1 in 'Unit1.pas';
type
{$M+}
IMyEvent = interface(IEvent<TNotifyEvent>)
procedure Add(const handler: TMethod);
end;
{$M-}
{$M+}
IMyEventMock = interface(IMyEvent)
procedure Add(const handler: TMethod);
end;
{$M-}
{$M+}
IEventContainer = interface(IInterface)
function GetEvent: IMyEvent;
procedure SetEvent(const Value: IMyEvent);
property Event: IMyEvent
read GetEvent
write SetEvent;
end;
{$M-}
{$M+}
ITestEventContainer = interface(IEventContainer)
function GetEvent: TMock<IMyEvent>;
procedure SetEvent(const …
Run Code Online (Sandbox Code Playgroud) 我正在为存储库构建 SQL 查询构建器。此构建器将查找查询的所有必需字段并创建 SQL 文本。为此,我正在使用 Format() 过程。但是,我在运行时无法创建必须传递给 Format 过程的 TVarRec 数组。
使用 Format('%s, %s', ['AString', 'AnotherString']);` 等常量构建这个数组很容易。但是我们必须如何在运行时创建它呢?
这是我的方法的简化版本:
procedure BuildString;
begin
FStrings := TStringList.Create;
FStrings.Add('String 1');
FStrings.Add('String 2');
FStrings.Add('String 3');
FFormatString := '%0:s, %1:s, %2:s';
SetLength(FFormatStringParams, FStrings.Count);
for I := 0 to FStrings.Count - 1 do
begin
aString := FStrings.Strings[I];
FFormatStringParams[I].VString := Addr(aString);
end;
ShowMessage(Format(FFormatString, FFormatStringParams));
end;
Run Code Online (Sandbox Code Playgroud)
但是当我运行它时,我收到错误“格式 '%0:s, %1:s, %2:s' 无效或与参数不兼容”
我知道我错误地构建了必须传递给 Format 过程的 TVarRec 数组。任何人都可以帮助我吗?
谢谢你。
我正在尝试在浏览器中使用Browerifiy,如果我使用独立选项它会暴露一个模块.我不想这样做.网站和文档似乎在我实际编译代码的任何地方都被切断了.没有人说过如何在浏览器属性中实际使用代码.
我有一个笨拙的任务:
browserify: {
standalone: {
src: [ '<%= yeoman.server %>/shared-components/**/*.js' ],
dest: '<%= yeoman.client %>/app/js/browserifed-shared-code.js',
/* Commented out, zero documentation on this. Can only expose one module it seems.
options: {
browserifyOptions: {
standalone: 'Utility' //Unable to say '**/*' error :-/
}
}
*/
},
Run Code Online (Sandbox Code Playgroud)
这似乎工作,它使这样的文件:
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';
var UrlController = function(){};
UrlController.test = function () {
return …
Run Code Online (Sandbox Code Playgroud) 我在寻找一种方式来轻松和简洁地写为Delphi下DUnitX测试框架间谍.
在过去,我使用非常难看的方式:
[TestFixture]
Test = class(TObject)
public
[test]
procedure Test1;
end;
TMyClass = class(TObject)
protected
procedure MyProcedure; virtual;
end;
TMyTestClass = class(TMyClass)
protected
fMyProcedureCalled : Boolean;
procedure MyProcedure; override;
end
procedure TMyTestClass.MyProcedure;
begin
fMyProcedureCalled := true;
inherited;
end;
procedure Test.Test1;
var aObj : TMyTestClass;
begin
TMyTestClass.Create;
Assert.IsTrue(aObj.fMyProcedureCalled);
end;
Run Code Online (Sandbox Code Playgroud)
所有这些代码都用于检查是否调用了一个过程.那太冗长了!
有没有办法写一个可以帮助我减少代码的间谍?
我正在使用Moq作为我的单元测试的模拟库.
它似乎很难找到Castle Windsor库,因为它给了我这个错误:
System.TypeInitializationException : Une exception a été levée par l'initialiseur de type pour 'Moq.Mock`1'.
----> System.TypeInitializationException : Une exception a été levée par l'initialiseur de type pour 'Moq.Proxy.CastleProxyFactory'.
----> System.IO.FileNotFoundException : Impossible de charger le fichier ou l'assembly 'Castle.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc' ou une de ses dépendances. Le fichier spécifié est introuvable.
à Moq.Mock`1.<InitializeInstance>b__24_0()
à Moq.PexProtector.Invoke(Action action)
à Moq.Mock`1.InitializeInstance()
à Moq.Mock`1.OnGetObject()
à Moq.Mock.GetObject()
à Moq.Mock.get_Object()
à Moq.Mock`1.get_Object()
à TecLib.Common.Tests.Infrastructure.CqrsRepositoryBaseTest.SetUp() dans C:\Users\Ludovic\Documents\Visual Studio 2015\Projects\TEC2\TecLib.Common.Tests\Infrastructure\CqrsRepositoryBaseTest.cs:ligne 38
--TypeInitializationException
à Moq.Proxy.CastleProxyFactory..ctor()
à …
Run Code Online (Sandbox Code Playgroud) 我必须在Delphi中对某些表单进行单元测试.我的老板要我编写测试来检查是否分配了事件.有太多我们必须对它们进行一些检查.
例如,我想检查一下
TMyForm.OnCreate = TMyForm.FormCreate.
Run Code Online (Sandbox Code Playgroud)
为此,我写道:
function TFMaitreTest.SameMethod(const Method1, Method2: TNotifyEvent; msg : string = ''): boolean;
begin
Assert.IsTrue(TEqualityComparer<TNotifyEvent>.Default.Equals(Method1, Method2), msg);
end;
Run Code Online (Sandbox Code Playgroud)
但是使用这种方式,我必须覆盖SameMethod
每种事件委托:TNotifyEvent,TDataSetEvent,...
然后我想到使用泛型,如下:
function TFMaitreTest.SameMethod<T>(const Method1, Method2: T; msg : string = ''): boolean;
Run Code Online (Sandbox Code Playgroud)
但这不编译.TEqualityComparer
需要一些通用约束,但不能为对象的过程定义通用约束.使用TMethod
约束也不起作用.也许这里有办法,但我还没找到.
然后,我想到了使用Rtti改变方法.我想比较使用Rtti的方法,但为此,我必须知道带字符串的方法的名称.
RttiType.GetMethod(methodName)
Run Code Online (Sandbox Code Playgroud)
这里methodName
是一个纯粹的字符串.如果我们重构并methodName
成为MyMethod
,我们有点搞砸了,必须在每个字符串使用的地方手动检查.我们希望编译时错误.它不容易出错.
C#具有lambda表达式的概念,它对于这些场景非常强大:
请参阅使用表达式获取方法的名称
如果将事件属性分配给特定过程,而不必为每种事件类型编写方法,我如何编写更通用的测试方法?
谢谢您的帮助.
我正在尝试编写一个spec实用程序库.
规范之一是TExpressionSpecification.基本上,它通过评估内部TExpression来实现规范模式.
其中一个TExpression是TPropertyExpression.它只是一个表达式,通过Rtti的名称获取属性的值.
我以最简单的方式实现它,但实在无法理解为什么它会向我抛出AV.
我悄悄地调试了调试器.所有类型都是它们应该是的.我只是不知道为什么TRttiProperty.GetValue破坏了破坏.
有人可以帮忙吗?单位规格;
interface
uses
Classes;
type
TPropertyExpression<TObjectType, TResultType> = class
private
FPropertyName: string;
public
constructor Create(aPropertyName: string); reintroduce;
function Evaluate(aObject: TObjectType): TResultType;
property PropertyName: string read FPropertyName write FPropertyName;
end;
procedure TestIt;
implementation
uses
Rtti;
constructor TPropertyExpression<TObjectType, TResultType>.Create(aPropertyName:
string);
begin
inherited Create;
PropertyName := aPropertyName;
end;
function TPropertyExpression<TObjectType, TResultType>.Evaluate(aObject:
TObjectType): TResultType;
var
aCtx : TRttiContext;
aModelType : TRttiType;
aResultType : TRttiType;
aProperty : TRttiProperty;
aValue : TValue;
begin
aCtx := TRttiContext.Create;
aModelType := aCtx.GetType(System.TypeInfo(TObjectType));
aResultType := …
Run Code Online (Sandbox Code Playgroud)