I am currently confused, if it is possible to compile an interface at runtime and add it to a "hardcoded" namespace.
Some code to explain:
using System;
using System.Runtime.CompilerServices;
using EngineCore;
namespace EngineCore
{
public interface iMobilePhones
{
string phoneNumber {get; set;}
string phoneRingtone {get; set;}
void CallNumber(string phoneNumber);
}
}
This is the runtime compiled interface, I want to add to the EngineCore namespace at runtime.
The compilation seems to work as expected and as you can see I compiled it using the EngineCore namespace.
using System;
using System.Runtime.CompilerServices;
using EngineCore;
namespace EngineCore
{
public class EQMobilePhoneCheap : iMobilePhones
{
//iMobilePhones interface members
private string PhoneNumber;
private string PhoneRingtone = "Default";
public string phoneNumber
{
get
{
return PhoneNumber;
}
set
{
PhoneNumber = value;
}
}
public string phoneRingtone
{
get
{
return PhoneRingtone;
}
set
{
PhoneRingtone = value;
}
}
//iMobilePhones interface functions
public void CallNumber(string phoneNumber)
{
}
}
}
This is the second runtime compiled code. As you can see, I am trying to use the iMobilePhones interface I compiled before.
But the compilation fails because iMobilePhones is not an interface of EngineCore
The actual question:
So I am wondering if there is a way to "register" the previously compiled interface iMobilePhones to the EngineCore namespace?
Thank you very much for reading.
Any suggestions are welcome.
You simply need to add a reference to the assembly containing the interface when you compile code that uses it.
Related
Summary:
I have a simple solution with two projects, e.g. ProjA and ProjB. In ProjA I have specified my custom the RTConfigure method for fluent configuration of the translation process using the Reinforeced.Typings tool for translating C# to TypeScript code. In ProjB I defined C# ViewModel classes that are intended for translation.
Problem:
In ProjB I defined three classes in three separate files and each of them belongs to their specific namespace. When using a global builder config by calling e.g. builder.UseModules(true, false) the produced code does not include fully qualified namespace names for the translated types that refer to types after the keyword extends and for types that are specified as members of another class (which belongs to another namespace different from the one of the used member type).
For example:
ProjB.Ns1.Class1
ProjB.Ns2.Class2
ProjB.Ns3.Class3
All three classes defines just two simple props, where Class3 differs a bit by containing one extra property with the type of Class1. Class2 inherits from Class1.
Here is the example code:
// Class1.cs
namespace ReinforcedTypings.DifferentNamespaces.Ns1
{
public class Class1
{
public int AnIntegerPropNs1 { get; set; }
public string AStringPropNs1 { get; set; }
}
}
// Class2.cs
using ReinforcedTypings.DifferentNamespaces.Ns1
namespace ReinforcedTypings.DifferentNamespaces.Ns2
{
public class Class2 : Class1
{
public int AnIntegerPropNs2 { get; set; }
public string AStringPropNs2 { get; set; }
}
}
// Class3.cs
using ReinforcedTypings.DifferentNamespaces.Ns1
namespace ReinforcedTypings.DifferentNamespaces.Ns3
{
public class Class3
{
public int AnIntegerPropNs3 { get; set; }
public string AStringPropNs3 { get; set; }
public Class1 AClass1PropNs3 { get; set; }
}
}
The configure method is very simple and is defined as follows:
public static class RTConfig
{
public static void Configure(ConfigurationBuilder builder)
{
var types = typeof(ReinforcedTypings.DifferentNamespaces.Ns1.Class1).Assembly.GetTypes().ToList();
builder.ExportAsClasses(types.Where(x => x.IsClass), c => c.WithAllFields().WithAllMethods().WithAllProperties());
builder.Global(c => c.UseModules(true, false));
// ^ commenting out this line will also cause a different error
}
}
I use the .xml configuration file to specify that the translation should all result in one file by setting the following option (false) as:
<RtDivideTypesAmongFiles>false</RtDivideTypesAmongFiles>
...and this results in the following TypeScript code in (translated.ts as set in the .xml configuration file):
export namespace ReinforcedTypings.DifferentNamespaces.Ns3 {
export class Class3
{
public AnIntegerPropNs3: number;
public AStringPropNs3: string;
public AClass1PropNs3: Class1; // <- error here
}
}
export namespace ReinforcedTypings.DifferentNamespaces.Ns2 {
export class Class2 extends Class1 // <- error here
{
public AnIntegerPropNs2: number;
public AStringPropNs2: string;
}
}
export namespace ReinforcedTypings.DifferentNamespaces.Ns1 {
export class Class1
{
public AnIntegerPropNs1: number;
public AStringPropNs1: string;
}
}
Please notice that Class1 type is missing the full namespace notation for its name after extends and in the translated property member private AClass1PropNs3: Class1; of the Class3.
This causes an issue in TypeScript as these types are not found due to not specifying the full (namespace) path name of the type.
Side issue observed:
When not working with UseModules, if you comment out that line, another issue will be found in the translated TypeScript code and it is due to the order of translated code, i.e. the Class1 will not be found in Class3 because it is used before its declaration.
Conclusion:
I did not go into the source of RT but I doubt there is an one issue with the UseModules(true, false) where second argument explicitly states not to discard the namespaces and another issue regarding the order of the code that gets outputted. Anyways, having the second argument value set to false one would expect to always and everywhere have the FQN for the used type. If I am mistaken of the usage of this config prop, then I propose it would be of great benefit to have such global config which would enforce the usage of FQN for all/desired types.
Definitely FQN issue is bug of RT and is fixed in version 1.4.6.
About side issue: see this GitHub Discussion
so I have a library Mine.SuperFun which calls stuff in the library SuperFun whose main namespace is SuperFun. The problem i'm having is that i can't address classes or basically anything in the SuperFun library inside classes in the Mine.SuperFun.XyZFoo namespaces
The only way to address them i have is doing stuff like:
using SuperFun_NiceClass = SuperFun.NiceClass;
using Mine.SuperFun {
...
SuperFun_NiceClass.DoStuff()
is there something i can do (besides changing the namespace in Mine library) to be able to address those classes directly?
You can use the global contextual keyword
What is the usage of global:: keyword in C#?
http://msdn.microsoft.com/en-us/library/cc713620.aspx
namespace Mine.SuperFun
{
public class My { public int a; }
}
namespace SuperFun
{
public class Theirs { public int a; }
}
namespace SomeProgram
{
public class Program
{
SuperFun.Theirs theirs;
global::Mine.SuperFun.My mine;
}
}
I have created an interface as shown below. The DTO object is a complex value object with 3 parameters.
public interface IOperation
{
DTO Operate(DTO ArchiveAndPurgeDTO);
}
I need people that impliment this interface to be able to inherit from the original Value object and extend it where required.
My assumption was that they could simply inherit the DTO object, add (for example) another property and use it in the same class that impliments this interface.
When I try to use the extended value object, Visual Studio complains that I am no longer implimenting the interface.
How can I impliment this functionality.
Thanks in advance for any ideas, and/or suggestions.
Gineer
Edit:
DTO Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Company.ArchiveAndPurge
{
public class DTO
{
public DTO(String FriendlyID)
{
friendlyId = FriendlyID;
}
private String friendlyId = String.Empty;
public String FriendlyId
{
get { return friendlyId; }
set { friendlyId = value; }
}
private String internalId = String.Empty;
public String InternalyId
{
get { return internalId; }
set { internalId = value; }
}
private Boolean archivedSuccessfully = false;
public Boolean ArchivedSuccessfully
{
get { return archivedSuccessfully; }
set { archivedSuccessfully = value; }
}
}
}
Extended DTO:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Company.MSO.ArchiveAndPurge
{
public class DTO: Company.ArchiveAndPurge.DTO
{
private Boolean requiresArchiving = true;
public Boolean RequiresArchiving
{
get { return requiresArchiving; }
set { requiresArchiving = value; }
}
}
}
Interface Implementation where VS Complains:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Company.ArchiveAndPurge.Contracts;
using Company.ArchiveAndPurge;
namespace Company.MSO.ArchiveAndPurge
{
public class ResolveFriendlyId: IOperation
{
#region IOperation Members
public DTO Operate(DTO ArchiveAndPurgeDTO)
{
ArchiveAndPurgeDTO.InternalyId = ArchiveAndPurgeDTO.FriendlyId;
return ArchiveAndPurgeDTO;
}
#endregion
}
}
As I understand it, you probably had something like:
public class ExtendedOperation : IOperation
{
public ExtendedDTO Operate(ExtendedDTO dto)
{
...
}
}
That doesn't work in two ways:
You can't change the return type when implementing an interface method
You can't change the parameter list when implementing an interface
In particular, you wouldn't be implementing IOperation in a way which would be compatible with code like this:
IOperation operation = new ExtendedOperation();
operation.Operate(new DTO());
I suspect you might want to make the interface generic:
public interface IOperation<T> where T : DTO
{
T Operate(T dto);
}
Use Generics:
public interface IOperation<T> where T : DTO
{
T Operate(T ArchiveAndPurgeDTO);
}
I have some strange problem. I have a solution with the following structure
http://i33.tinypic.com/10fbzbq.jpg
As you can see when i wonna import the VDB.Common.RequestAndResponses it gives an error.
The namespace of dat Class Library is VDB.Common.RequestAndResponses.
I am new in c# , so it could be that i forgot something stupid.
I strongly suspect that Base.cs (the only C# file shown in the VDB.Common.RequestAndResponses project) doesn't actually declare a type in the VDB.Common.RequestAndResponses namespace - or that it only declares an internal (rather than public) type.
For example, note that the code you're creating is under the VDB.Client.Infrastructure project, but is only declaring a class in the Agatha namespace - not VDB.Client.Infrastructure.Agatha, which may be what you were intending. Do you have the same kind of thing in Base.cs, perhaps?
Without seeing the code in Base.cs, we can't see what's wrong though. If you could just post a snippet of that - just the namespace and class declaration - that would be helpful.
Note that although a class library has a default namespace, this isn't prepended to whatever the source file actually declares. In other words, in a library of Acme.Widgets, if you had a declaration of:
namespace Web
{
public class Button {}
}
that would only declare the type Web.Button, not Acme.Widgets.Web.Button.
EDIT: The OP's "answer" confirms what I thought... basically it's not declaring a namespace at all. It should look like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Agatha.Common;
namespace VDB.Common.RequestAndResponses
{
public abstract class BaseRequest :Request
{
// Code
}
public abstract class BaseResponse : Response
{
// Code
}
}
I would also strongly advise that these classes should be put in two separate files, BaseRequest.cs and BaseResponse.cs. I'm also pretty surprised to see a reference to Agatha.Common - shouldn't that be VDB.Common.Agatha or something like that?
Right click on the "VDB.Common.RequestAndResponses" reference in solution explorer and choose "Show in object browser", make sure the namespace is found there with the exact spelling and capitalization.
Try to use the Base class in the client code and hover over it and allow the Visual Studio IDE to prompt you to add the appropriate namespace. The namespace defined in the Base class could be different to what you think.
EDIT
As Jon as demonstrated in the 2nd part of his answer - the name of the code file does not automatically correspond to the namespace.
The Base.cs file looks like this.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Agatha.Common;
public abstract class BaseRequest :Request
{
public string UserName { get; set; }
public string UserDomainName { get; set; }
public string ClientLanguageCode { get; set; }
public DateTime ClientCreated { get; set; }
public DateTime ClientSent { get; set; }
public DateTime ServerReceived { get; set; }
public DateTime ServerProcessed { get; set; }
public void BeforeSend(IUserContext context)
{
ClientSent = DateTime.UtcNow;
UserName = context.UserName;
UserDomainName = context.UserDomainName;
ClientLanguageCode = context.LanguageCode;
}
}
public abstract class BaseResponse : Response
{
public DateTime ServerCreated { get; set; }
public DateTime ServerProcessed { get; set; }
public string[] ValidationErrors { get; set; }
public bool IsValid
{
get { return Exception == null & !ValidationErrors.Any(); }
}
}
I have created a class in c# and made the com visible property is true. But, i could not see the its properties at visual basic 6.0. what could be a problem? please help me
Define a public interface that is also ComVisible, and have your class implement that.
Then use tlbexp.exe to generate a type libary from your C# assembly:
tlbexp ComServer.dll /out:ComServer.tlb
You need to add a reference to the type library from VB6, not the assembly. How does VB6 know where your assembly actually is then? Regasm is how. It is the equivalent of regsvr32 for .net assemblies.
regasm ComServer.dll
Do you apply ComVisible(true) to class?
As long as you make your class ComVisible in Properties (of Visual Studio 2005 or 2008, or set the ComVisible attribute to True in the Assembly file), you should be able to see your class in VB6. To get intellisense you need to declare an interface, give it a GUID, and implement it as shown in the example code below (Note: you have to create your own unique GUID's for both the interface and the concrete class.
using System.Runtime.InteropServices;
using System.Drawing;
namespace example_namespace
{
[Guid("1F436D05-1111-3340-8050-E70166C7FC86")]
public interface Circle_interface
{
[DispId(1)]
int Radius
{
get;
set;
}
[DispId(2)]
int X
{
get;
set;
}
[DispId(3)]
int Y
{
get;
set;
}
}
[Guid("4EDA5D35-1111-4cd8-9EE8-C543163D4F75"),
ProgId("example_namespace.Circle_interface"),
ClassInterface(ClassInterfaceType.None)]
public class Circle : Circle_interface
{
private int _radius;
private Point _position;
private bool _autoRedeye;
public int Radius
{
get { return _radius; }
set { _radius = value; }
}
public int X
{
get { return _position.X; }
set { _position.X = value; }
}
public int Y
{
get { return _position.Y; }
set { _position.Y = value; }
}
}
}